@bernierllc/openapi-schema-builder
v1.0.1
Published
Pure atomic OpenAPI schema construction utilities with type safety for OpenAPI 3.0.x and 3.1.0
Downloads
107
Readme
@bernierllc/openapi-schema-builder
Pure atomic OpenAPI schema construction utilities with type safety for OpenAPI 3.0.x and 3.1.0.
Features
- Type-Safe Schema Building - Full TypeScript support with strict typing
- OpenAPI 3.0.x & 3.1.0 Support - Compatible with modern OpenAPI specifications
- Zero Dependencies - Pure atomic package with no external dependencies
- Comprehensive Validation - Built-in schema and component validation
- Schema Type Builders - Convenient helpers for creating schema objects
- Flexible API - Clean, intuitive builder pattern
Installation
npm install @bernierllc/openapi-schema-builderUsage
Quick Start
import { OpenAPISchemaBuilder, SchemaTypes } from '@bernierllc/openapi-schema-builder';
const builder = new OpenAPISchemaBuilder();
// Create basic components
const info = builder.createInfo('My API', '1.0.0', 'A sample API');
const server = builder.createServer('https://api.example.com');
// Create a schema
const userSchema = SchemaTypes.object({
id: SchemaTypes.integer({ minimum: 1 }),
email: SchemaTypes.string({ format: 'email' }),
name: SchemaTypes.string({ minLength: 1, maxLength: 100 })
}, ['id', 'email']); // Required fields
// Create an operation
const getUser = builder.createOperation('get', {
summary: 'Get user by ID',
parameters: [
builder.createParameter('id', 'path', SchemaTypes.integer())
],
responses: builder.createResponses({
'200': builder.createResponse(
'Success',
builder.createJsonContent(userSchema)
)
})
});API Reference
Core API
OpenAPISchemaBuilder
The main builder class for constructing OpenAPI components.
Constructor
const builder = new OpenAPISchemaBuilder({
version: '3.0.3', // Optional: OpenAPI version (default: '3.0.3')
strictValidation: true // Optional: Enable strict validation (default: true)
});Info Object
const info = builder.createInfo(
'Pet Store API',
'1.0.0',
'A sample API for pet store operations',
{
contact: {
name: 'API Support',
email: '[email protected]',
url: 'https://example.com/support'
},
license: {
name: 'MIT',
url: 'https://opensource.org/licenses/MIT'
},
termsOfService: 'https://example.com/terms'
}
);Server Objects
// Simple server
const server = builder.createServer('https://api.example.com', 'Production server');
// Server with variables
const dynamicServer = builder.createServer(
'https://{environment}.example.com',
'Environment-specific server',
{
environment: {
default: 'api',
enum: ['api', 'staging', 'dev'],
description: 'Server environment'
}
}
);Path and Operation Objects
// Create a path with operations
const userPath = builder.createPath({
get: builder.createOperation('get', {
summary: 'Get user',
operationId: 'getUser',
tags: ['users'],
parameters: [
builder.createParameter('id', 'path', SchemaTypes.string(), {
description: 'User ID',
required: true
})
],
responses: builder.createResponses({
'200': builder.createResponse('Success', builder.createJsonContent(userSchema)),
'404': builder.createResponse('Not Found')
})
}),
put: builder.createOperation('put', {
summary: 'Update user',
operationId: 'updateUser',
requestBody: builder.createRequestBody(
builder.createJsonContent(userSchema),
true, // required
'User object to update'
),
responses: builder.createResponses({
'200': builder.createResponse('Success'),
'404': builder.createResponse('Not Found')
})
})
});Parameters
// Path parameter
const pathParam = builder.createParameter('id', 'path', SchemaTypes.string(), {
description: 'Resource ID',
required: true // Path parameters are always required
});
// Query parameter
const queryParam = builder.createParameter('limit', 'query', SchemaTypes.integer(), {
description: 'Maximum number of results',
example: 10
});
// Header parameter
const headerParam = builder.createParameter('X-API-Key', 'header', SchemaTypes.string(), {
description: 'API key for authentication'
});Responses
// Simple response
const response = builder.createResponse('Success');
// Response with content
const jsonResponse = builder.createResponse(
'User object',
builder.createJsonContent(userSchema, { id: 1, email: '[email protected]', name: 'John' })
);
// Response with headers
const responseWithHeaders = builder.createResponse(
'Success',
builder.createJsonContent(userSchema),
{
'X-Rate-Limit': {
name: 'X-Rate-Limit',
in: 'header',
schema: SchemaTypes.integer()
}
}
);Security Schemes
// API Key
const apiKey = builder.createApiKeyScheme('X-API-Key', 'header', 'API key authentication');
// Bearer Token
const bearer = builder.createBearerScheme('JWT', 'JWT bearer token authentication');
// HTTP Basic
const basic = builder.createBasicScheme('HTTP basic authentication');
// OAuth2
const oauth2 = builder.createSecurityScheme('oauth2', {
flows: {
authorizationCode: {
authorizationUrl: 'https://auth.example.com/authorize',
tokenUrl: 'https://auth.example.com/token',
scopes: {
'read': 'Read access',
'write': 'Write access',
'admin': 'Admin access'
}
}
}
});Tags
const tag = builder.createTag(
'users',
'User management endpoints',
builder.createExternalDocs('https://docs.example.com/users', 'User API Documentation')
);Schema Type Builders
The SchemaTypes utility provides convenient methods for creating schema objects:
Primitive Types
import { SchemaTypes } from '@bernierllc/openapi-schema-builder';
// String
const name = SchemaTypes.string({
minLength: 1,
maxLength: 100,
pattern: '^[a-zA-Z ]+$'
});
const email = SchemaTypes.string({
format: 'email'
});
// Number
const price = SchemaTypes.number({
minimum: 0,
maximum: 99999.99,
multipleOf: 0.01
});
// Integer
const age = SchemaTypes.integer({
minimum: 0,
maximum: 150
});
// Boolean
const isActive = SchemaTypes.boolean();Complex Types
// Array
const tags = SchemaTypes.array(
SchemaTypes.string(),
{ minItems: 1, maxItems: 10, uniqueItems: true }
);
// Object
const address = SchemaTypes.object({
street: SchemaTypes.string(),
city: SchemaTypes.string(),
zipCode: SchemaTypes.string({ pattern: '^\\d{5}$' })
}, ['street', 'city']); // Required fields
// Nested objects
const user = SchemaTypes.object({
id: SchemaTypes.integer({ minimum: 1 }),
name: SchemaTypes.string({ minLength: 1 }),
email: SchemaTypes.string({ format: 'email' }),
address: address,
tags: tags
}, ['id', 'name', 'email']);Composition
// oneOf
const petType = SchemaTypes.oneOf([
SchemaTypes.ref('Dog'),
SchemaTypes.ref('Cat')
]);
// anyOf
const flexible = SchemaTypes.anyOf([
SchemaTypes.string(),
SchemaTypes.number()
]);
// allOf (inheritance)
const extendedUser = SchemaTypes.allOf([
SchemaTypes.ref('BaseUser'),
SchemaTypes.object({
role: SchemaTypes.string({ enum: ['admin', 'user'] })
})
]);Enums and Nullability
// Enum
const status = SchemaTypes.enum(['active', 'inactive', 'pending'], 'string');
// Nullable
const optionalName = SchemaTypes.nullable(SchemaTypes.string());References
// Short form (automatically prefixes with #/components/schemas/)
const userRef = SchemaTypes.ref('User');
// Results in: { $ref: '#/components/schemas/User' }
// Full path form
const customRef = SchemaTypes.ref('#/components/schemas/User');Schema Utilities
import { schemaUtils } from '@bernierllc/openapi-schema-builder';
// Check if object is a reference
const isRef = schemaUtils.isReference({ $ref: '#/components/schemas/User' }); // true
// Merge schemas
const merged = schemaUtils.mergeSchemas(baseSchema, extensionSchema);
// Normalize reference
const normalized = schemaUtils.normalizeRef('#/components/schemas/User');
// Validate reference
const isValid = schemaUtils.validateReference('#/components/schemas/User', components);
// Generate example from schema
const example = schemaUtils.generateExample(userSchema);
// Get property names
const properties = schemaUtils.getPropertyNames(schema);Validation
import { OpenAPISchemaBuilder } from '@bernierllc/openapi-schema-builder';
const builder = new OpenAPISchemaBuilder();
// Validate complete OpenAPI schema
const schema = {
openapi: '3.0.3',
info: { title: 'API', version: '1.0.0' },
paths: {}
};
const result = builder.validateSchema(schema);
if (!result.valid) {
console.error('Validation errors:', result.errors);
}
// Validate individual components
const componentResult = builder.validateComponent(userSchema, 'schemas');Complete Example
import {
OpenAPISchemaBuilder,
SchemaTypes,
type OpenAPIObject
} from '@bernierllc/openapi-schema-builder';
const builder = new OpenAPISchemaBuilder({ version: '3.0.3' });
// Define schemas
const userSchema = SchemaTypes.object({
id: SchemaTypes.integer({ minimum: 1 }),
username: SchemaTypes.string({ minLength: 3, maxLength: 20 }),
email: SchemaTypes.string({ format: 'email' }),
createdAt: SchemaTypes.string({ format: 'date-time' }),
roles: SchemaTypes.array(SchemaTypes.string({ enum: ['admin', 'user', 'guest'] }))
}, ['id', 'username', 'email']);
const errorSchema = SchemaTypes.object({
code: SchemaTypes.integer(),
message: SchemaTypes.string()
}, ['code', 'message']);
// Build OpenAPI specification
const spec: OpenAPIObject = {
openapi: '3.0.3',
info: builder.createInfo(
'User API',
'1.0.0',
'RESTful API for user management'
),
servers: [
builder.createServer('https://api.example.com', 'Production'),
builder.createServer('https://staging-api.example.com', 'Staging')
],
paths: {
'/users': {
get: builder.createOperation('get', {
summary: 'List users',
operationId: 'listUsers',
tags: ['users'],
parameters: [
builder.createParameter('limit', 'query', SchemaTypes.integer({ minimum: 1, maximum: 100 }), {
description: 'Maximum number of users to return'
}),
builder.createParameter('offset', 'query', SchemaTypes.integer({ minimum: 0 }), {
description: 'Number of users to skip'
})
],
responses: builder.createResponses({
'200': builder.createResponse(
'Success',
builder.createJsonContent(
SchemaTypes.array(userSchema)
)
),
'default': builder.createResponse(
'Error',
builder.createJsonContent(errorSchema)
)
})
}),
post: builder.createOperation('post', {
summary: 'Create user',
operationId: 'createUser',
tags: ['users'],
requestBody: builder.createRequestBody(
builder.createJsonContent(userSchema),
true,
'User to create'
),
responses: builder.createResponses({
'201': builder.createResponse(
'Created',
builder.createJsonContent(userSchema)
),
'400': builder.createResponse(
'Bad Request',
builder.createJsonContent(errorSchema)
)
})
})
},
'/users/{id}': {
get: builder.createOperation('get', {
summary: 'Get user by ID',
operationId: 'getUserById',
tags: ['users'],
parameters: [
builder.createParameter('id', 'path', SchemaTypes.integer({ minimum: 1 }))
],
responses: builder.createResponses({
'200': builder.createResponse(
'Success',
builder.createJsonContent(userSchema)
),
'404': builder.createResponse('Not Found')
})
})
}
},
components: {
schemas: {
User: userSchema,
Error: errorSchema
},
securitySchemes: {
bearerAuth: builder.createBearerScheme('JWT')
}
},
security: [
{ bearerAuth: [] }
],
tags: [
builder.createTag('users', 'User management operations')
]
};
// Validate the specification
const validation = builder.validateSchema(spec);
if (validation.valid) {
console.log('OpenAPI specification is valid!');
console.log(JSON.stringify(spec, null, 2));
} else {
console.error('Validation errors:', validation.errors);
}TypeScript Support
This package is written in TypeScript and provides full type definitions:
import type {
OpenAPIObject,
InfoObject,
PathItemObject,
OperationObject,
SchemaObject,
ParameterObject,
ResponseObject,
SecuritySchemeObject
} from '@bernierllc/openapi-schema-builder';Best Practices
1. Use Schema References
For reusable schemas, use the components section and references:
const userRef = SchemaTypes.ref('User');
// In operations
responses: builder.createResponses({
'200': builder.createResponse(
'Success',
builder.createJsonContent(userRef)
)
})2. Validate Early
Validate your schemas during development:
const validation = builder.validateSchema(spec);
if (!validation.valid) {
throw new Error(`Invalid OpenAPI spec: ${validation.errors.map(e => e.message).join(', ')}`);
}3. Use Type Builders
Prefer SchemaTypes helpers over manual schema construction:
// Good
const email = SchemaTypes.string({ format: 'email' });
// Less ideal
const email = { type: 'string', format: 'email' };4. Document Your API
Always provide descriptions for operations, parameters, and schemas:
const operation = builder.createOperation('get', {
summary: 'Get user by ID',
description: 'Retrieves a single user by their unique identifier',
// ...
});Error Handling
import { OpenAPISchemaError, ValidationError, ReferenceError } from '@bernierllc/openapi-schema-builder';
try {
const normalized = schemaUtils.normalizeRef('invalid-ref');
} catch (error) {
if (error instanceof ReferenceError) {
console.error('Invalid reference:', error.reference);
}
}Integration Status
- Logger Integration: Not applicable - This is a pure atomic utility package with no runtime behavior requiring logging. As a foundational schema builder with zero dependencies, logger integration is not needed.
- Docs-Suite: Ready - TypeScript types and JSDoc documentation
- NeverHub Integration: Not applicable - This is a pure atomic utility package providing schema construction functions. As a foundational package with no runtime orchestration or service communication, NeverHub integration via @bernierllc/neverhub-adapter is not needed.
Related Packages
This package is the foundation for:
@bernierllc/jsdoc-openapi-parser- Parse JSDoc to OpenAPI@bernierllc/zod-openapi-converter- Convert Zod schemas to OpenAPI@bernierllc/openapi-merger- Merge multiple OpenAPI specifications@bernierllc/openapi-generator- Generate OpenAPI from code
License
Copyright (c) 2025 Bernier LLC. All rights reserved.
This package is proprietary software licensed for use only within the scope of the project it was delivered for.
