Skip to content

Examples

This page contains end-to-end examples showing common use cases for the Apitomy Data Models library. Each example is provided in both Java and TypeScript.


Build an OpenAPI Document from Scratch

Create a complete OpenAPI 3.0 document programmatically, including info, paths, operations, request bodies, responses, and schema definitions.

import io.apitomy.datamodels.Library;
import io.apitomy.datamodels.models.ModelType;
import io.apitomy.datamodels.models.openapi.v3x.v30.OpenApi30Document;

// Create the document
OpenApi30Document doc = (OpenApi30Document) Library.createDocument(ModelType.OPENAPI30);

// Info
doc.setInfo(doc.createInfo());
doc.getInfo().setTitle("Pet Store API");
doc.getInfo().setVersion("1.0.0");
doc.getInfo().setDescription("A sample API for managing pets");

// Contact
doc.getInfo().setContact(doc.getInfo().createContact());
doc.getInfo().getContact().setName("API Support");
doc.getInfo().getContact().setEmail("support@example.com");

// Server
doc.addServer(doc.createServer());
doc.getServers().get(0).setUrl("https://api.example.com/v1");

// Paths
doc.setPaths(doc.createPaths());

// POST /pets
doc.getPaths().addItem("/pets", doc.getPaths().createPathItem());
var petsPath = doc.getPaths().getItem("/pets");
petsPath.setPost(petsPath.createOperation());
var createPet = petsPath.getPost();
createPet.setOperationId("createPet");
createPet.setSummary("Create a pet");

// Request body
createPet.setRequestBody(createPet.createRequestBody());
createPet.getRequestBody().setRequired(true);
createPet.getRequestBody().addMediaType(
    "application/json",
    createPet.getRequestBody().createMediaType()
);

// 201 response
createPet.addResponse("201", createPet.createResponse());
createPet.getResponse("201").setDescription("Pet created successfully");

// Components with a Pet schema
doc.setComponents(doc.createComponents());
doc.getComponents().addSchema("Pet", doc.getComponents().createSchema());
var petSchema = doc.getComponents().getSchemas().get("Pet");
petSchema.setType("object");
petSchema.addProperty("id", petSchema.createSchema());
petSchema.getProperties().get("id").setType("integer");
petSchema.addProperty("name", petSchema.createSchema());
petSchema.getProperties().get("name").setType("string");

// Tags
doc.addTag(doc.createTag());
doc.getTags().get(0).setName("pets");
doc.getTags().get(0).setDescription("Pet operations");

// Write to JSON
String json = Library.writeDocumentToJSONString(doc);
System.out.println(json);
import { Library, ModelType, OpenApi30Document } from '@apitomy/data-models';

// Create the document
const doc = Library.createDocument(ModelType.OPENAPI30) as OpenApi30Document;

// Info
doc.setInfo(doc.createInfo());
doc.getInfo().setTitle('Pet Store API');
doc.getInfo().setVersion('1.0.0');
doc.getInfo().setDescription('A sample API for managing pets');

// Contact
doc.getInfo().setContact(doc.getInfo().createContact());
doc.getInfo().getContact().setName('API Support');
doc.getInfo().getContact().setEmail('support@example.com');

// Server
doc.addServer(doc.createServer());
doc.getServers()[0].setUrl('https://api.example.com/v1');

// Paths
doc.setPaths(doc.createPaths());

// POST /pets
doc.getPaths().addItem('/pets', doc.getPaths().createPathItem());
const petsPath = doc.getPaths().getItem('/pets');
petsPath.setPost(petsPath.createOperation());
const createPet = petsPath.getPost();
createPet.setOperationId('createPet');
createPet.setSummary('Create a pet');

// Request body
createPet.setRequestBody(createPet.createRequestBody());
createPet.getRequestBody().setRequired(true);
createPet.getRequestBody().addMediaType(
    'application/json',
    createPet.getRequestBody().createMediaType()
);

// 201 response
createPet.addResponse('201', createPet.createResponse());
createPet.getResponse('201').setDescription('Pet created successfully');

// Components with a Pet schema
doc.setComponents(doc.createComponents());
doc.getComponents().addSchema('Pet', doc.getComponents().createSchema());
const petSchema = doc.getComponents().getSchemas().get('Pet');
petSchema.setType('object');
petSchema.addProperty('id', petSchema.createSchema());
petSchema.getProperties().get('id').setType('integer');
petSchema.addProperty('name', petSchema.createSchema());
petSchema.getProperties().get('name').setType('string');

// Tags
doc.addTag(doc.createTag());
doc.getTags()[0].setName('pets');
doc.getTags()[0].setDescription('Pet operations');

// Write to JSON
const json = JSON.stringify(Library.writeNode(doc), null, 2);
console.log(json);

List All API Endpoints

Read a document and extract every endpoint (HTTP method + path) along with its operation details.

import io.apitomy.datamodels.Library;
import io.apitomy.datamodels.TraverserDirection;
import io.apitomy.datamodels.models.Document;
import io.apitomy.datamodels.models.openapi.OpenApiOperation;
import io.apitomy.datamodels.models.openapi.OpenApiPathItem;
import io.apitomy.datamodels.models.visitors.CombinedVisitorAdapter;
import java.util.ArrayList;
import java.util.List;

Document doc = Library.readDocumentFromJSONString(json);

class Endpoint {
    String method;
    String path;
    String operationId;
    String summary;

    Endpoint(String method, String path, String operationId, String summary) {
        this.method = method;
        this.path = path;
        this.operationId = operationId;
        this.summary = summary;
    }
}

List<Endpoint> endpoints = new ArrayList<>();

Library.visitTree(doc, new CombinedVisitorAdapter() {
    @Override
    public void visitOperation(OpenApiOperation node) {
        // The parent is a PathItem — get the HTTP method from the parent property name
        String method = node.parentPropertyName().toUpperCase();
        // The grandparent property name is the path string
        String path = ((OpenApiPathItem) node.parent()).mapPropertyName();
        endpoints.add(new Endpoint(method, path, node.getOperationId(), node.getSummary()));
    }
}, TraverserDirection.down);

System.out.println("Found " + endpoints.size() + " endpoints:");
for (Endpoint ep : endpoints) {
    System.out.printf("  %-6s %-30s %s%n", ep.method, ep.path,
        ep.operationId != null ? ep.operationId : "(no operationId)");
}
import {
    Library, TraverserDirection, Document,
    CombinedVisitorAdapter, OpenApiOperation, OpenApiPathItem
} from '@apitomy/data-models';

const doc: Document = Library.readDocument(json);

interface Endpoint {
    method: string;
    path: string;
    operationId: string | null;
    summary: string | null;
}

const endpoints: Endpoint[] = [];

class EndpointCollector extends CombinedVisitorAdapter {
    visitOperation(node: OpenApiOperation): void {
        // The parent is a PathItem — get the HTTP method from the parent property name
        const method = node.parentPropertyName().toUpperCase();
        // The grandparent property name is the path string
        const path = (node.parent() as OpenApiPathItem).mapPropertyName();
        endpoints.push({
            method,
            path,
            operationId: node.getOperationId(),
            summary: node.getSummary(),
        });
    }
}

Library.visitTree(doc, new EndpointCollector(), TraverserDirection.down);

console.log(`Found ${endpoints.length} endpoints:`);
endpoints.forEach(ep => {
    const id = ep.operationId ?? '(no operationId)';
    console.log(`  ${ep.method.padEnd(6)} ${ep.path.padEnd(30)} ${id}`);
});

Validate and Report Problems

Read a document, validate it, and produce a formatted report of all issues found.

import io.apitomy.datamodels.Library;
import io.apitomy.datamodels.models.Document;
import io.apitomy.datamodels.validation.ValidationProblem;
import io.apitomy.datamodels.validation.ValidationProblemSeverity;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

Document doc = Library.readDocumentFromJSONString(json);
List<ValidationProblem> problems = Library.validate(doc, null);

if (problems.isEmpty()) {
    System.out.println("Document is valid.");
} else {
    // Group by severity
    Map<ValidationProblemSeverity, List<ValidationProblem>> bySeverity =
        problems.stream().collect(Collectors.groupingBy(p -> p.severity));

    // Print summary
    System.out.println("Validation Results:");
    System.out.println("  Errors:   " + bySeverity.getOrDefault(ValidationProblemSeverity.high, List.of()).size());
    System.out.println("  Warnings: " + bySeverity.getOrDefault(ValidationProblemSeverity.medium, List.of()).size());

    // Print details
    System.out.println("\nProblems:");
    for (ValidationProblem p : problems) {
        System.out.printf("  [%s] %s%n", p.severity, p.message);
        System.out.printf("    Path: %s%n", p.nodePath);
        System.out.printf("    Code: %s%n", p.errorCode);
    }
}
import { Library, Document, ValidationProblem } from '@apitomy/data-models';

const doc: Document = Library.readDocument(json);
const problems: ValidationProblem[] = Library.validate(doc, null);

if (problems.length === 0) {
    console.log('Document is valid.');
} else {
    // Group by severity
    const errors = problems.filter(p => p.severity.toString() === 'high');
    const warnings = problems.filter(p => p.severity.toString() === 'medium');

    // Print summary
    console.log('Validation Results:');
    console.log(`  Errors:   ${errors.length}`);
    console.log(`  Warnings: ${warnings.length}`);

    // Print details
    console.log('\nProblems:');
    problems.forEach(p => {
        console.log(`  [${p.severity}] ${p.message}`);
        console.log(`    Path: ${p.nodePath}`);
        console.log(`    Code: ${p.errorCode}`);
    });
}

Upgrade OpenAPI 2.0 to 3.0

Read a Swagger 2.0 document, transform it to OpenAPI 3.0, and write out the result.

import io.apitomy.datamodels.Library;
import io.apitomy.datamodels.models.Document;
import io.apitomy.datamodels.models.ModelType;

// Read the Swagger 2.0 document
String swaggerJson = """
    {
      "swagger": "2.0",
      "info": { "title": "Legacy API", "version": "1.0" },
      "host": "api.example.com",
      "basePath": "/v1",
      "schemes": ["https"],
      "consumes": ["application/json"],
      "produces": ["application/json"],
      "paths": {
        "/users": {
          "get": {
            "operationId": "listUsers",
            "summary": "List all users",
            "parameters": [
              {
                "name": "limit",
                "in": "query",
                "type": "integer",
                "description": "Maximum number of users to return"
              }
            ],
            "responses": {
              "200": {
                "description": "A list of users",
                "schema": { "$ref": "#/definitions/UserList" }
              }
            }
          }
        }
      },
      "definitions": {
        "User": {
          "type": "object",
          "properties": {
            "id": { "type": "integer" },
            "name": { "type": "string" }
          }
        },
        "UserList": {
          "type": "array",
          "items": { "$ref": "#/definitions/User" }
        }
      }
    }
    """;

Document swagger = Library.readDocumentFromJSONString(swaggerJson);
Document openApi30 = Library.transformDocument(swagger, ModelType.OPENAPI30);

String result = Library.writeDocumentToJSONString(openApi30);
System.out.println(result);
// Output has "openapi": "3.0.3", "servers" array, "components/schemas", etc.
import { Library, Document, ModelType } from '@apitomy/data-models';

// Read the Swagger 2.0 document
const swaggerJson = {
    swagger: '2.0',
    info: { title: 'Legacy API', version: '1.0' },
    host: 'api.example.com',
    basePath: '/v1',
    schemes: ['https'],
    consumes: ['application/json'],
    produces: ['application/json'],
    paths: {
        '/users': {
            get: {
                operationId: 'listUsers',
                summary: 'List all users',
                parameters: [
                    {
                        name: 'limit',
                        in: 'query',
                        type: 'integer',
                        description: 'Maximum number of users to return',
                    },
                ],
                responses: {
                    '200': {
                        description: 'A list of users',
                        schema: { $ref: '#/definitions/UserList' },
                    },
                },
            },
        },
    },
    definitions: {
        User: {
            type: 'object',
            properties: {
                id: { type: 'integer' },
                name: { type: 'string' },
            },
        },
        UserList: {
            type: 'array',
            items: { $ref: '#/definitions/User' },
        },
    },
};

const swagger: Document = Library.readDocument(swaggerJson);
const openApi30: Document = Library.transformDocument(swagger, ModelType.OPENAPI30);

const result = JSON.stringify(Library.writeNode(openApi30), null, 2);
console.log(result);
// Output has "openapi": "3.0.3", "servers" array, "components/schemas", etc.

Implement a Custom Reference Resolver

Resolve external $ref references by fetching content from a map (simulating a file system or database).

import io.apitomy.datamodels.Library;
import io.apitomy.datamodels.models.Document;
import io.apitomy.datamodels.models.Node;
import io.apitomy.datamodels.refs.IReferenceResolver;
import io.apitomy.datamodels.refs.ResolvedReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Map;

// Simulated external schemas
Map<String, String> externalSchemas = Map.of(
    "https://schemas.example.com/address.json", """
        {
          "type": "object",
          "properties": {
            "street": { "type": "string" },
            "city": { "type": "string" },
            "zipCode": { "type": "string" }
          }
        }
        """,
    "https://schemas.example.com/phone.json", """
        {
          "type": "object",
          "properties": {
            "number": { "type": "string" },
            "type": { "type": "string", "enum": ["home", "work", "mobile"] }
          }
        }
        """
);

// Create a resolver that looks up schemas from the map
IReferenceResolver resolver = new IReferenceResolver() {
    private final ObjectMapper mapper = new ObjectMapper();

    @Override
    public ResolvedReference resolveRef(String reference, Node from) {
        String schemaJson = externalSchemas.get(reference);
        if (schemaJson == null) {
            return null;
        }
        try {
            Object json = mapper.readTree(schemaJson);
            return ResolvedReference.fromJson(json);
        } catch (Exception e) {
            return null;
        }
    }
};

// Register and dereference
Library.addReferenceResolver(resolver);
Document doc = Library.readDocumentFromJSONString(apiJson);
Document dereferenced = Library.dereferenceDocument(doc);
Library.removeReferenceResolver(resolver);

// The dereferenced document has external $refs replaced with actual content
String result = Library.writeDocumentToJSONString(dereferenced);
System.out.println(result);
import {
    Library, Document, Node,
    IReferenceResolver, ResolvedReference
} from '@apitomy/data-models';

// Simulated external schemas
const externalSchemas: Record<string, any> = {
    'https://schemas.example.com/address.json': {
        type: 'object',
        properties: {
            street: { type: 'string' },
            city: { type: 'string' },
            zipCode: { type: 'string' },
        },
    },
    'https://schemas.example.com/phone.json': {
        type: 'object',
        properties: {
            number: { type: 'string' },
            type: { type: 'string', enum: ['home', 'work', 'mobile'] },
        },
    },
};

// Create a resolver that looks up schemas from the map
class MapReferenceResolver implements IReferenceResolver {
    resolveRef(reference: string, from: Node): ResolvedReference | null {
        const schema = externalSchemas[reference];
        if (!schema) {
            return null;
        }
        return ResolvedReference.fromJson(schema);
    }
}

// Register and dereference
const resolver = new MapReferenceResolver();
Library.addReferenceResolver(resolver);
const doc: Document = Library.readDocument(apiJson);
const dereferenced: Document = Library.dereferenceDocument(doc);
Library.removeReferenceResolver(resolver);

// The dereferenced document has external $refs replaced with actual content
const result = JSON.stringify(Library.writeNode(dereferenced), null, 2);
console.log(result);