OpenAPI v3 validators and utilities
npm install openapi-policeA powerful JavaScript library providing OpenAPI v3 validators and utilities for comprehensive API validation and compliance checking. Built on top of jsonpolice, it extends JSON Schema validation with OpenAPI-specific features like parameter style parsing and discriminator validation.



- ✅ OpenAPI v3 Compliance: Full support for OpenAPI 3.0+ and 3.1 specifications
- ✅ Parameter Validation: Handle path, query, header, and cookie parameters with style parsing
- ✅ Schema Extensions: OpenAPI-specific schema enhancements (discriminator, nullable, etc.)
- ✅ Style Parsing: Support for parameter serialization styles (matrix, label, form, simple, etc.)
- ✅ Format Validation: Extended format validation for OpenAPI types
- ✅ TypeScript Support: Full TypeScript definitions included
- ✅ Modern ES Modules: Supports both ESM and CommonJS
- ✅ Built on jsonpolice: Leverages proven JSON Schema validation foundation with JSON Schema 2020-12 support
``bashnpm
npm install openapi-police
Quick Start
$3
`javascript
import { SchemaObject } from 'openapi-police';const schema = new SchemaObject({
type: 'object',
properties: {
id: { type: 'string', format: 'uuid' },
name: { type: 'string', nullable: true },
tags: {
type: 'array',
items: { type: 'string' },
uniqueItems: true
}
},
required: ['id']
});
try {
const data = {
id: '123e4567-e89b-12d3-a456-426614174000',
name: null, // nullable is allowed
tags: ['api', 'validation']
};
const validated = await schema.validate(data);
console.log('Valid data:', validated);
} catch (error) {
console.error('Validation failed:', error.message);
}
`$3
`javascript
import { ParameterObject } from 'openapi-police';// Query parameter with simple style (comma-separated)
const queryParam = new ParameterObject({
name: 'tags',
in: 'query',
required: true,
schema: {
type: 'array',
items: { type: 'string' }
},
style: 'simple',
explode: false
});
// Validate automatically parses the parameter style: ?tags=api,validation
const validated = await queryParam.validate('api,validation');
console.log(validated); // ['api', 'validation']
// Path parameter with simple style
const pathParam = new ParameterObject({
name: 'userId',
in: 'path',
required: true,
schema: { type: 'string', format: 'uuid' }
});
// Direct validation - parsing happens internally
await pathParam.validate('123e4567-e89b-12d3-a456-426614174000');
`API Reference
$3
Extends standard JSON Schema with OpenAPI-specific features.
Constructors:
`javascript
// For simple schemas without $ref
import { StaticSchemaObject } from 'openapi-police';
new StaticSchemaObject(schema)// For schemas with $ref - requires jsonref
import { StaticSchemaObject } from 'openapi-police';
import * as refs from 'jsonref';
new StaticSchemaObject(await refs.parse(schema, options))
`Parameters:
-
schema (object): OpenAPI Schema ObjectValidation Options:
-
coerceTypes (boolean): Convert string values to the target type (default: false for SchemaObject, true for ParameterObject)
- setDefault (boolean): Apply default values from schema
- removeAdditional (boolean): Remove properties not in schema
- context ('read' | 'write'): Validation context for readOnly/writeOnlyFeatures:
- nullable: Allow null values in addition to specified type
- discriminator: Polymorphism support with discriminator mapping
- format: Extended format validation for OpenAPI types
- readOnly/writeOnly: Context-aware validation
Example:
`javascript
import { StaticSchemaObject } from 'openapi-police';const schema = new StaticSchemaObject({
type: 'string',
nullable: true,
format: 'email'
});
await schema.validate(null); // Valid (nullable)
await schema.validate('user@example.com'); // Valid (email format)
await schema.validate('invalid-email'); // Throws ValidationError
`$3
Handles OpenAPI parameter validation with automatic style parsing.
Constructor:
`javascript
new ParameterObject(parameter)
`Parameters:
-
parameter (object): OpenAPI Parameter ObjectKey Methods:
-
validate(data, options?, path?): Validates data and automatically parses parameter style
- Automatically enables coerceTypes by default
- Automatically parses style-encoded strings based on parameter schema type
- Returns the validated and parsed dataImportant Note:
⚠️ Do not call
parseStyle() directly - it's an internal method. Use validate() which handles parsing automatically.Supported Locations:
-
path - Path parameters (e.g., /users/{id})
- query - Query string parameters (e.g., ?name=value)
- header - HTTP header parameters
- cookie - Cookie parametersStyle Support:
| Location | Supported Styles | Default |
|----------|------------------|---------|
| path | matrix, label, simple | simple |
| query | simple, spaceDelimited, pipeDelimited, deepObject | simple |
| header | simple, form, spaceDelimited, pipeDelimited | simple |
| cookie | form, simple, spaceDelimited, pipeDelimited | form |
Note: The implementation differs from OpenAPI spec which specifies
form as default for query parameters. This library uses simple for query arrays and deepObject for query objects.Example:
`javascript
import { ParameterObject } from 'openapi-police';const param = new ParameterObject({
name: 'filter',
in: 'query',
schema: {
type: 'object',
properties: {
status: { type: 'string' },
priority: { type: 'string' }
}
},
style: 'deepObject',
explode: true
});
// Validate: ?filter[status]=active&filter[priority]=high
const parsed = await param.validate('filter[status]=active&filter[priority]=high');
console.log(parsed); // { status: 'active', priority: 'high' }
`$3
Handles validation for OpenAPI MediaType objects with content-type aware validation.
Constructor:
`javascript
new MediaTypeObject(mediaType, contentType)
`Parameters:
-
mediaType (object): OpenAPI MediaType Object
- contentType (string): The content type (e.g., 'application/json')Example:
`javascript
import { MediaTypeObject } from 'openapi-police';const mediaType = new MediaTypeObject({
schema: {
type: 'object',
properties: {
message: { type: 'string' }
}
}
}, 'application/json');
await mediaType.validate({ message: 'Hello' });
`Usage Examples
$3
`javascript
import { SchemaObject } from 'openapi-police';const petSchema = new SchemaObject({
discriminator: {
propertyName: 'petType',
mapping: {
cat: '#/components/schemas/Cat',
dog: '#/components/schemas/Dog'
}
},
oneOf: [
{ $ref: '#/components/schemas/Cat' },
{ $ref: '#/components/schemas/Dog' }
]
});
// The discriminator will automatically select the correct schema
// based on the petType property value
const catData = {
petType: 'cat',
name: 'Fluffy',
huntingSkill: 'excellent'
};
const validated = await petSchema.validate(catData);
`$3
`javascript
import { ParameterObject } from 'openapi-police';// Matrix style for path parameters
const matrixParam = new ParameterObject({
name: 'coordinates',
in: 'path',
required: true,
schema: {
type: 'object',
properties: {
lat: { type: 'number' },
lng: { type: 'number' }
}
},
style: 'matrix',
explode: true
});
// Validate with type coercion (strings → numbers)
// Input: ;lat=50.1;lng=8.7
const coords = await matrixParam.validate(';lat=50.1;lng=8.7');
console.log(coords); // { lat: 50.1, lng: 8.7 }
// Note: ParameterObject automatically enables coerceTypes
// Label style for path parameters
const labelParam = new ParameterObject({
name: 'tags',
in: 'path',
required: true,
schema: {
type: 'array',
items: { type: 'string' }
},
style: 'label',
explode: false
});
// Validate with label style: .red.green.blue
const tags = await labelParam.validate('.red.green.blue');
console.log(tags); // ['red', 'green', 'blue']
`$3
`javascript
import { ParameterObject } from 'openapi-police';// Header parameter
const headerParam = new ParameterObject({
name: 'X-API-Version',
in: 'header',
required: true,
schema: {
type: 'string',
pattern: '^v\\d+$'
}
});
await headerParam.validate('v1'); // Valid
await headerParam.validate('invalid'); // Throws ValidationError
// Cookie parameter with form style (default)
const cookieParam = new ParameterObject({
name: 'session',
in: 'cookie',
schema: {
type: 'object',
properties: {
userId: { type: 'string' },
token: { type: 'string' }
}
},
style: 'form',
explode: false
});
// Validate cookie value: "session=userId,123,token,abc123"
const session = await cookieParam.validate('session=userId,123,token,abc123');
console.log(session); // { userId: '123', token: 'abc123' }
`$3
`javascript
import { SchemaObject } from 'openapi-police';const schema = new SchemaObject({
type: 'integer',
nullable: true,
minimum: 0,
maximum: 100
});
await schema.validate(null); // Valid (nullable)
await schema.validate(50); // Valid (integer in range)
await schema.validate(150); // Throws ValidationError (exceeds maximum)
await schema.validate('50'); // Throws ValidationError (wrong type)
`Error Handling
openapi-police provides detailed validation errors:
`javascript
import { SchemaObject, ParameterObject } from 'openapi-police';try {
const schema = new SchemaObject({
type: 'object',
properties: {
email: { type: 'string', format: 'email' }
},
required: ['email']
});
await schema.validate({ email: 'invalid-email' });
} catch (error) {
console.log(error.name); // 'ValidationError'
console.log(error.message); // Detailed error description
console.log(error.path); // JSON Pointer to invalid property
}
`TypeScript Support
Full TypeScript definitions are included:
`typescript
import { SchemaObject, ParameterObject } from 'openapi-police';interface APIResponse {
id: string;
data: any;
nullable?: string | null;
}
const responseSchema = new SchemaObject({
type: 'object',
properties: {
id: { type: 'string', format: 'uuid' },
data: {},
nullable: { type: 'string', nullable: true }
},
required: ['id', 'data']
});
const validated: APIResponse = await responseSchema.validate(responseData);
`Integration with OpenAPI Specifications
openapi-police is designed to work seamlessly with OpenAPI specifications:
`javascript
import { SchemaObject, ParameterObject } from 'openapi-police';// From OpenAPI spec
const openApiSpec = {
paths: {
'/users/{userId}': {
get: {
parameters: [
{
name: 'userId',
in: 'path',
required: true,
schema: { type: 'string', format: 'uuid' }
},
{
name: 'include',
in: 'query',
schema: {
type: 'array',
items: { type: 'string' }
},
style: 'simple',
explode: false
}
]
}
}
}
};
// Create validators from spec
const pathParam = new ParameterObject(openApiSpec.paths['/users/{userId}'].get.parameters[0]);
const queryParam = new ParameterObject(openApiSpec.paths['/users/{userId}'].get.parameters[1]);
// Use in request validation
await pathParam.validate('123e4567-e89b-12d3-a456-426614174000');
await queryParam.validate('profile,settings,preferences'); // simple style: comma-separated
`OpenAPI 3.1 Features
openapi-police now supports OpenAPI 3.1 specification features:
$3
OpenAPI 3.1 aligns with JSON Schema Draft 2020-12, providing enhanced validation capabilities:
`javascript
import { SchemaObject } from 'openapi-police';const schema = new SchemaObject({
type: 'object',
properties: {
// OpenAPI 3.1 can specify the JSON Schema dialect
name: { type: 'string' },
tags: {
type: 'array',
items: { type: 'string' },
prefixItems: [{ const: 'primary' }] // JSON Schema 2020-12 feature
}
}
});
`$3
OpenAPI 3.1 introduces webhooks for describing incoming HTTP requests:
`javascript
const openApiDoc = {
openapi: '3.1.0',
info: { title: 'Webhook API', version: '1.0.0' },
paths: {},
webhooks: {
'newPet': {
post: {
requestBody: {
content: {
'application/json': {
schema: {
type: 'object',
properties: {
id: { type: 'integer' },
name: { type: 'string' }
}
}
}
}
},
responses: {
'200': { description: 'Webhook processed' }
}
}
}
}
};
`$3
Now supports the
deepObject style for complex query parameters:`javascript
import { ParameterObject } from 'openapi-police';const deepParam = new ParameterObject({
name: 'filter',
in: 'query',
style: 'deepObject',
explode: true,
schema: {
type: 'object',
properties: {
status: { type: 'string' },
priority: { type: 'string' },
category: { type: 'string' }
}
}
});
// Validate: ?filter[status]=active&filter[priority]=high&filter[category]=api
const parsed = await deepParam.validate('filter[status]=active&filter[priority]=high&filter[category]=api');
console.log(parsed); // { status: 'active', priority: 'high', category: 'api' }
// Note: deepObject style does not support array values - each key can only have one value
// If the same key appears multiple times, the last value overwrites previous ones
`$3
Enhanced support for parameter content validation:
`javascript
import { ParameterObject } from 'openapi-police';const contentParam = new ParameterObject({
name: 'data',
in: 'query',
content: {
'application/json': {
schema: {
type: 'object',
properties: {
filters: {
type: 'array',
items: { type: 'string' }
},
options: {
type: 'object',
properties: {
limit: { type: 'integer', minimum: 1 },
offset: { type: 'integer', minimum: 0 }
}
}
}
}
},
'application/xml': {
schema: { type: 'string' }
}
}
});
// Validate with content type
const jsonData = {
filters: ['active', 'verified'],
options: { limit: 10, offset: 0 }
};
await contentParam.validate(jsonData, { contentType: 'application/json' });
`$3
OpenAPI 3.1 documents can specify their JSON Schema dialect:
`javascript
const openApi31Doc = {
openapi: '3.1.0',
info: { title: 'Modern API', version: '2.0.0' },
jsonSchemaDialect: 'https://json-schema.org/draft/2020-12/schema',
paths: {
'/items': {
get: {
parameters: [{
name: 'search',
in: 'query',
schema: {
type: 'object',
patternProperties: {
'^[a-zA-Z]+$': { type: 'string' }
}
}
}]
}
}
}
};
`Validation Options
All validate methods accept an optional
options parameter with the following properties:Common Options:
-
coerceTypes (boolean): Automatically convert strings to target types (numbers, booleans, integers)
- Default: false for SchemaObject, true for ParameterObject
- setDefault (boolean): Apply default values from the schema
- removeAdditional (boolean): Remove properties not defined in the schema
- context ('read' | 'write'): Validation context for readOnly/writeOnly propertiesParameterObject Specific:
-
parseStyle (boolean): Enable/disable automatic parameter style parsing (default: true)
- contentType (string): Specify content type for parameter content validationExample:
`javascript
import { StaticSchemaObject } from 'openapi-police';const schema = new StaticSchemaObject({
type: 'object',
properties: {
age: { type: 'integer' },
name: { type: 'string', default: 'Anonymous' }
}
});
// With type coercion and defaults
const data = await schema.validate(
{ age: '25' },
{ coerceTypes: true, setDefault: true }
);
console.log(data); // { age: 25, name: 'Anonymous' }
`Troubleshooting
$3
"style" Error with ParameterObject
- This typically means you're using an incompatible style/type combination
- Check the Style Support table to see which styles are supported for your parameter location
- Verify your parameter schema type matches what the style expects
Type Validation Errors
- By default, SchemaObject does NOT coerce types
- For ParameterObject, set
coerceTypes: true in options if you need string→number conversion
- Remember: ParameterObject automatically enables coerceTypes by default"Cannot find module" Errors
- Make sure you're importing from 'openapi-police' not './dist/index.js'
- Check that you're using ESM imports (
import) not CommonJS (require)Discriminator Validation Fails
- Ensure your discriminator propertyName exists in the data
- Verify the discriminator value matches one of the mapped schemas
- For $ref resolution, consider using
jsonref to parse your schemas firstPerformance Tips
1. Reuse validator instances - Create validators once and reuse them
2. Leverage caching - Use shared registries for external schema references
3. Validate early - Validate parameters and request bodies before processing
4. Use appropriate styles - Choose the most efficient parameter style for your use case
Browser Support
openapi-police works in all modern browsers and Node.js environments. It requires:
- ES2015+ support
- Promise support
- JSON.parse/JSON.stringify
License
MIT License - see the LICENSE file for details.
Contributing
Contributions are welcome! Please ensure all tests pass:
`bash
pnpm install
pnpm test
pnpm run coverage
``