Description
I encountered an issue with resolving references in Swagger Editor, as described in this issue. To address this, I wrote a simple TypeScript function that resolves $ref references in OpenAPI YAML files. Here’s the solution:
/* eslint-disable @typescript-eslint/no-explicit-any */
import fs from 'fs';
import path from 'path';
import YAML from 'yaml';
export function resolveOpenApiReferences(basePath: string, nameYaml: string) {
const resolveReferences = (obj: any, dir: string) => {
for (const key in obj) {
if (typeof obj[key] === 'object') {
resolveReferences(obj[key], dir);
} else if (key === '$ref' && !obj[key].startsWith('#')) {
const refPath = path.resolve(dir, obj[key]);
const fileContent = fs.readFileSync(refPath, 'utf8');
const fileData = YAML.parse(fileContent);
Object.assign(obj, fileData);
delete obj[key];
resolveReferences(obj, path.dirname(refPath)); // Resolve nested $ref
}
}
};
const fileContent = fs.readFileSync(path.resolve(basePath, nameYaml), 'utf8');
const swaggerDocument = YAML.parse(fileContent);
resolveReferences(swaggerDocument, basePath);
return swaggerDocument;
}
Explanation
This function, resolveOpenApiReferences, recursively resolves $ref references in an OpenAPI YAML document. Here's a brief overview of how it works:
Reading the YAML File: The function reads the main OpenAPI YAML file from the specified base path.
Parsing YAML: It parses the file content into a JavaScript object using the yaml package.
Resolving References: The nested resolveReferences function iterates through the object and looks for $ref keys that do not start with # (indicating internal references). When it finds such a reference, it reads the referenced file, parses its content, and replaces the $ref key with the actual data from the referenced file. This process is repeated recursively to handle nested references.
This approach ensures that all external references in your OpenAPI document are resolved correctly, making it easier to work with Swagger Editor.
Usage with Express
You can integrate this function with an Express application to serve your OpenAPI documentation. Here's an example of how to do it:
import express from 'express';
import swaggerUi from 'swagger-ui-express';
import { resolveOpenApiReferences } from './path/to/your/resolveOpenApiReferences';
const app = express();
const swaggerDocument = resolveOpenApiReferences('./swagger/', 'openapi.yaml');
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument));
app.listen(3000, () => {
console.log('Server is running on http://localhost:3000');
});
In this example, the resolveOpenApiReferences function is used to load and resolve the OpenAPI document before setting up the Swagger UI middleware in an Express application. This allows you to serve your fully resolved OpenAPI documentation at the /api-docs endpoint.
Feel free to use and modify this function to fit your needs!