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
Advanced reference resolution capabilities for bundling external $ref pointers and dereferencing all references inline, providing complete control over how API definitions handle references.
Bundle external $ref pointers into the main document, resolving references to external files while preserving internal references.
/**
* Bundle up the given API definition, resolving any external $ref pointers in the process
* Internal references are preserved, external files are loaded and embedded
* @returns Promise resolving to bundled OpenAPI document
*/
async bundle(): Promise<OpenAPI.Document>;Usage Examples:
import OASNormalize from "oas-normalize";
// API definition with external references
const apiWithExternalRefs = {
openapi: "3.0.0",
info: { title: "Pet Store", version: "1.0.0" },
paths: {
"/pets": {
get: {
responses: {
"200": {
description: "Successful response",
content: {
"application/json": {
schema: { $ref: "./schemas/pet.json" } // External reference
}
}
}
}
}
}
},
components: {
schemas: {
Error: { // Internal schema preserved
type: "object",
properties: {
code: { type: "integer" },
message: { type: "string" }
}
}
}
}
};
const oas = new OASNormalize(apiWithExternalRefs, { enablePaths: true });
const bundled = await oas.bundle();
// External ./schemas/pet.json is now embedded in the bundled document
// Internal references like #/components/schemas/Error remain as-is
console.log(bundled.components.schemas.Pet); // Now contains the content from pet.jsonDereference all $ref pointers, both internal and external, creating a fully expanded document with no references.
/**
* Dereference the given API definition, resolving all $ref pointers inline
* Creates a fully expanded document with no remaining references
* @returns Promise resolving to dereferenced OpenAPI document
*/
async dereference(): Promise<OpenAPI.Document>;Usage Examples:
// API definition with internal references
const apiWithRefs = {
openapi: "3.0.0",
info: { title: "Pet Store", version: "1.0.0" },
paths: {
"/pets": {
post: {
requestBody: {
$ref: "#/components/requestBodies/Pet" // Internal reference
},
responses: {
"200": {
description: "Success",
content: {
"application/json": {
schema: { $ref: "#/components/schemas/Pet" } // Internal reference
}
}
}
}
}
}
},
components: {
schemas: {
Pet: {
type: "object",
properties: {
name: { type: "string" },
category: { $ref: "#/components/schemas/Category" } // Nested reference
}
},
Category: {
type: "object",
properties: {
id: { type: "integer" },
name: { type: "string" }
}
}
},
requestBodies: {
Pet: {
description: "Pet object that needs to be added",
required: true,
content: {
"application/json": {
schema: { $ref: "#/components/schemas/Pet" }
}
}
}
}
}
};
const oas = new OASNormalize(apiWithRefs);
const dereferenced = await oas.dereference();
// All $ref pointers are now resolved inline
console.log(dereferenced.paths['/pets'].post.requestBody);
// Contains the full requestBody object instead of { $ref: "..." }
console.log(dereferenced.paths['/pets'].post.requestBody.content['application/json'].schema);
// Contains the full Pet schema with Category schema inlinedLegacy alias for the dereference method, maintained for backward compatibility.
/**
* Dereference the given API definition
* @deprecated Use dereference() instead. Will be removed in a future release.
* @returns Promise resolving to dereferenced OpenAPI document
*/
async deref(): Promise<OpenAPI.Document>;Usage Examples:
// Deprecated usage - still works but not recommended
const oas = new OASNormalize(apiSpec);
const dereferenced = await oas.deref();
// Preferred usage
const preferred = await oas.dereference();Bundling resolves only external file references, keeping internal references intact:
// Before bundling
const spec = {
paths: {
"/pets": {
get: {
responses: {
"200": {
schema: { $ref: "./external-schema.json" } // External - will be resolved
},
"400": {
schema: { $ref: "#/components/schemas/Error" } // Internal - preserved
}
}
}
}
}
};
const bundled = await new OASNormalize(spec, { enablePaths: true }).bundle();
// After bundling:
// - ./external-schema.json content is embedded
// - #/components/schemas/Error reference remains as $refDereferencing resolves all references, creating a fully expanded document:
// Before dereferencing
const spec = {
paths: {
"/pets": {
get: {
responses: {
"200": { schema: { $ref: "#/components/schemas/Pet" } }
}
}
}
},
components: {
schemas: {
Pet: {
properties: {
category: { $ref: "#/components/schemas/Category" }
}
},
Category: { type: "object", properties: { name: { type: "string" } } }
}
}
};
const dereferenced = await new OASNormalize(spec).dereference();
// After dereferencing:
// - All $ref pointers are replaced with actual content
// - Category schema is inlined within Pet schema
// - No references remain in the documentBoth bundling and dereferencing automatically handle Postman collection conversion:
const postmanCollection = {
info: { name: "API Collection" },
item: [/* collection items */]
};
// Postman collections are automatically converted to OpenAPI first
const bundled = await new OASNormalize(postmanCollection).bundle();
const dereferenced = await new OASNormalize(postmanCollection).dereference();
// Both results are OpenAPI documents, not Postman collections
console.log(bundled.openapi); // "3.0.0"
console.log(dereferenced.openapi); // "3.0.0"Both operations are cached to improve performance:
const oas = new OASNormalize(complexSpec);
// First call performs the operation
const bundled1 = await oas.bundle();
// Second call returns cached result
const bundled2 = await oas.bundle();
console.log(bundled1 === bundled2); // true
// Same applies to dereference
const deref1 = await oas.dereference();
const deref2 = await oas.dereference();
console.log(deref1 === deref2); // trueconst specWithBadRef = {
openapi: "3.0.0",
paths: {
"/pets": {
get: {
responses: {
"200": {
schema: { $ref: "./nonexistent-file.json" }
}
}
}
}
}
};
try {
await new OASNormalize(specWithBadRef, { enablePaths: true }).bundle();
} catch (error) {
console.error("Failed to resolve external reference:", error.message);
}const specWithFileRef = {
openapi: "3.0.0",
paths: {
"/pets": {
get: {
parameters: [{
schema: { $ref: "/etc/passwd" } // Attempting to read system file
}]
}
}
}
};
// Without enablePaths, this will fail
try {
await new OASNormalize(specWithFileRef).bundle();
} catch (error) {
console.error(error.message); // "Unable to resolve $ref pointer..."
}Reference resolution works seamlessly with validation:
const specWithRefs = {
// API spec with various $ref pointers
};
const oas = new OASNormalize(specWithRefs);
// Validate the bundled version
const bundled = await oas.bundle();
await new OASNormalize(bundled).validate();
// Or validate the dereferenced version
const dereferenced = await oas.dereference();
await new OASNormalize(dereferenced).validate();
// Direct validation also works (resolves references internally)
await oas.validate();Install with Tessl CLI
npx tessl i tessl/npm-oas-normalize