Tooling for converting, validating, and parsing OpenAPI, Swagger, and Postman API definitions
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Comprehensive validation system with detailed error reporting, contextual messages, and customizable validation rules for OpenAPI, Swagger, and Postman API definitions.
Validate API definitions with comprehensive error reporting and contextual information pointing to specific line numbers and issues.
/**
* Validate a given API definition with detailed error reporting
* Supports OpenAPI 3.x, Swagger 2.0, and Postman collections
* @param opts - Optional validation configuration
* @returns Promise resolving to validation result if valid, throws ValidationError if invalid
*/
async validate(opts?: {
parser?: ParserOptions;
}): Promise<ValidationResult>;
interface ValidationResult {
valid: boolean;
warnings: WarningDetails[];
errors: ErrorDetails[];
}
interface ErrorDetails {
message: string;
path: string;
location?: {
line: number;
column: number;
};
}
interface WarningDetails {
message: string;
path: string;
rule: string;
}Usage Examples:
import OASNormalize from "oas-normalize";
// Basic validation
const oas = new OASNormalize(apiSpec);
try {
const result = await oas.validate();
console.log('✅ API definition is valid!');
if (result.warnings.length > 0) {
console.warn('⚠️ Warnings found:', result.warnings);
}
} catch (error) {
console.error('❌ Validation failed:');
console.error(error.message);
}// Validation with custom rules
const oas = new OASNormalize(apiSpec);
try {
const result = await oas.validate({
parser: {
validate: {
rules: {
openapi: {
'path-parameters-not-in-path': 'warning', // Treat as warning instead of error
'unused-components': 'off', // Disable this rule
'missing-example': 'error' // Enforce examples
}
}
}
}
});
if (result.warnings.length) {
console.warn('🚸 The API is valid but has some warnings:');
result.warnings.forEach(warning => {
console.warn(` - ${warning.message} (${warning.rule})`);
});
} else {
console.log('🍭 The API is valid with no warnings!');
}
} catch (error) {
console.error('❌ Validation failed:', error.message);
}Validates different API definition formats with automatic conversion as needed:
// OpenAPI 3.x validation
const openapi = {
openapi: "3.0.0",
info: { title: "Pet Store", version: "1.0.0" },
paths: {}
};
await new OASNormalize(openapi).validate();
// Swagger 2.0 validation
const swagger = {
swagger: "2.0",
info: { title: "Pet Store", version: "1.0.0" },
paths: {}
};
await new OASNormalize(swagger).validate();
// Postman collection validation (converts to OpenAPI first)
const postman = {
info: { name: "Collection" },
item: []
};
await new OASNormalize(postman).validate();Validation errors include contextual information with line numbers and specific issue locations:
const invalidSpec = {
openapi: "3.0.0",
info: { title: "API" }, // Missing required version field
servers: [
{ urll: "http://petstore.swagger.io/v2" } // Typo: should be "url"
],
paths: {}
};
try {
await new OASNormalize(invalidSpec).validate();
} catch (error) {
console.error(error.message);
// Output includes:
// OpenAPI schema validation failed.
//
// REQUIRED must have required property 'version'
//
// 2 | "info": {
// > 3 | "title": "API"
// | ^ ☹️ version is missing here!
// 4 | },
//
// REQUIRED must have required property 'url'
//
// 6 | "servers": [
// > 7 | {
// | ^ ☹️ url is missing here!
// 8 | "urll": "http://petstore.swagger.io/v2"
// 9 | }
}Enable colorized error messages for better readability in terminal environments:
const oas = new OASNormalize(invalidSpec, {
colorizeErrors: true
});
try {
await oas.validate();
} catch (error) {
// Error message will include ANSI color codes for:
// - Red highlighting for error locations
// - Yellow for warning text
// - Green for line numbers
// - Bold formatting for key information
console.error(error.message);
}Configure validation behavior with custom rulesets:
const validationOptions = {
parser: {
validate: {
rules: {
openapi: {
// Path parameter rules
'path-parameters-not-in-path': 'warning',
'path-parameters-defined-but-not-used': 'error',
// Schema rules
'unused-components': 'warning',
'missing-example': 'off',
'schema-names-camel-case': 'error',
// Security rules
'security-schemes-defined': 'error',
'security-requirements-defined': 'warning',
// Documentation rules
'operation-description': 'warning',
'parameter-description': 'off'
}
}
}
}
};
const result = await oas.validate(validationOptions);error: Validation fails, throws ValidationErrorwarning: Validation succeeds but includes warnings in resultoff: Rule is disabled completelyCommon OpenAPI validation rules that can be configured:
const commonRules = {
// Path and parameter validation
'path-parameters-not-in-path': 'error',
'path-parameters-defined-but-not-used': 'warning',
'duplicate-path-parameters': 'error',
// Schema validation
'unused-components': 'warning',
'missing-example': 'warning',
'schema-names-camel-case': 'off',
'required-properties-schema': 'error',
// Operation validation
'operation-id-unique': 'error',
'operation-id-case-convention': 'warning',
'operation-description': 'warning',
'operation-summary': 'off',
// Response validation
'response-schema-defined': 'error',
'success-response-defined': 'error',
// Security validation
'security-schemes-defined': 'error',
'security-requirements-defined': 'warning'
};All validation failures throw ValidationError instances:
import { ValidationError } from "oas-normalize/lib/errors";
try {
await oas.validate();
} catch (error) {
if (error instanceof ValidationError) {
console.error('Validation Error:', error.message);
console.error('Error Name:', error.name); // "ValidationError"
} else {
console.error('Unexpected Error:', error);
}
}const unsupportedSpec = {
// Missing format indicators
info: { title: "Unknown" }
};
try {
await new OASNormalize(unsupportedSpec).validate();
} catch (error) {
console.error(error.message); // "The supplied API definition is unsupported."
console.log(error instanceof ValidationError); // true
}const swagger12 = {
swagger: "1.2", // Unsupported version
info: { title: "Old API" }
};
try {
await new OASNormalize(swagger12).validate();
} catch (error) {
console.error(error.message); // "Swagger v1.2 is unsupported."
}Validation works seamlessly with other OAS Normalize operations:
const oas = new OASNormalize(apiSpec);
// Validate after conversion
const converted = await oas.convert();
await new OASNormalize(converted).validate();
// Validate after bundling
const bundled = await oas.bundle();
await new OASNormalize(bundled).validate();
// Validate after dereferencing
const dereferenced = await oas.dereference();
await new OASNormalize(dereferenced).validate();
// Direct validation (handles conversion internally)
await oas.validate();const specWithCircularRef = {
openapi: "3.0.0",
info: { title: "API", version: "1.0.0" },
components: {
schemas: {
Node: {
type: "object",
properties: {
value: { type: "string" },
child: { $ref: "#/components/schemas/Node" } // Circular reference
}
}
}
},
paths: {}
};
// Circular references are handled gracefully
const result = await new OASNormalize(specWithCircularRef).validate();
console.log('✅ Circular references validated successfully');const specWithExternalRefs = {
openapi: "3.0.0",
info: { title: "API", version: "1.0.0" },
paths: {
"/pets": {
get: {
responses: {
"200": {
content: {
"application/json": {
schema: { $ref: "./pet-schema.json" }
}
}
}
}
}
}
}
};
// Validate with external reference resolution
const oas = new OASNormalize(specWithExternalRefs, { enablePaths: true });
await oas.validate(); // Resolves and validates external referencesconst specs = [spec1, spec2, spec3];
const validationResults = await Promise.allSettled(
specs.map(spec => new OASNormalize(spec).validate())
);
validationResults.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`✅ Spec ${index + 1} is valid`);
} else {
console.error(`❌ Spec ${index + 1} failed:`, result.reason.message);
}
});Install with Tessl CLI
npx tessl i tessl/npm-oas-normalize