Generating OpenAPI Documents
OpenApiDocumentFactory is the single entry point. It accepts an ApiDocument and returns an OpenAPI document as a plain JavaScript object — no file I/O, no side effects.
generate(document, options?)
Returns the OpenAPI document directly.
import { OpenApiDocumentFactory } from '@opra/openapi';
const openApiDoc = OpenApiDocumentFactory.generate(apiDocument, {
version: '3.1', // '3.0' (default) or '3.1'
});
Options
| Option | Type | Default | Description |
|---|---|---|---|
version | '3.0' | '3.1' | '3.0' | Target OpenAPI spec version. Produces 3.0.3 or 3.1.0 in the openapi field. |
scope | string | undefined | When set, only types, fields, and parameters that pass .inScope(scope) are included. Useful for generating separate public / internal / admin API specs from the same document. |
generateWithWarnings(document, options?)
Same as generate() but also returns a warnings array — a list of OPRA constructs that have no exact OpenAPI equivalent and were either skipped or approximated.
const { document, warnings } = OpenApiDocumentFactory.generateWithWarnings(apiDocument);
if (warnings.length) {
console.warn('OpenAPI generation warnings:');
warnings.forEach(w => console.warn(' •', w));
}
What triggers a warning
QUERYandSEARCHmethods — these HTTP methods are not part of the OpenAPI 3.x path item spec and cannot be represented; those operations are skipped.- Duplicate operations — when two operations resolve to the same
METHOD /pathcombination, only the first one is kept and a warning is recorded. - Unknown DataType kinds — any custom
DataTypesubclass that isn'tComplexType,MappedType,MixinType,EnumType,ArrayType,UnionType, orSimpleTypeis mapped to an empty schema{}.
Version differences
| Feature | 3.0 | 3.1 |
|---|---|---|
openapi field value | 3.0.3 | 3.1.0 |
| Nullable fields | nullable: true alongside type | type: ['string', 'null'] (JSON Schema–style) |
Both versions are generated from the same input; only the nullable representation differs in the output.
Serving the document
The output is a plain, JSON-serialisable object. How you serve it is up to you — use any HTTP framework:
import express from 'express';
import { OpenApiDocumentFactory } from '@opra/openapi';
const app = express();
app.get('/openapi.json', (_req, res) => {
const doc = OpenApiDocumentFactory.generate(apiDocument);
res.json(doc);
});
Serving with Swagger UI (Express)
npm install swagger-ui-express
import swaggerUi from 'swagger-ui-express';
import { OpenApiDocumentFactory } from '@opra/openapi';
const spec = OpenApiDocumentFactory.generate(apiDocument);
app.use('/docs', swaggerUi.serve, swaggerUi.setup(spec));
Serving with Scalar (Express)
npm install @scalar/express-api-reference
import { apiReference } from '@scalar/express-api-reference';
import { OpenApiDocumentFactory } from '@opra/openapi';
const spec = OpenApiDocumentFactory.generate(apiDocument);
app.use('/docs', apiReference({ content: spec }));
NestJS integration
In a NestJS application, call OpenApiDocumentFactory after the app is initialised, then serve the result:
import { NestFactory } from '@nestjs/core';
import { OpraHttpModule } from '@opra/nestjs-http';
import { OpenApiDocumentFactory } from '@opra/openapi';
import swaggerUi from 'swagger-ui-express';
import { AppModule } from './app.module.js';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
// Obtain the ApiDocument from the OPRA NestJS module
const opraModule = app.get(OpraHttpModule);
const { document, warnings } = OpenApiDocumentFactory.generateWithWarnings(
opraModule.document,
{ version: '3.1' },
);
if (warnings.length) warnings.forEach(w => console.warn(w));
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(document));
await app.listen(3000);
}
bootstrap();
Writing to a file
To save the spec to disk (useful for CI validation, versioned spec files, or client code generation pipelines):
import { writeFileSync } from 'node:fs';
import { OpenApiDocumentFactory } from '@opra/openapi';
const doc = OpenApiDocumentFactory.generate(apiDocument);
writeFileSync('openapi.json', JSON.stringify(doc, null, 2));
Scope filtering
When your ApiDocument is shared between multiple audiences — public API, internal API, admin API — use the scope option to produce separate specs:
// Fields and parameters decorated with @ApiField({ scope: 'internal' })
// will only appear in the internal spec.
const publicSpec = OpenApiDocumentFactory.generate(apiDocument, {
scope: 'public',
});
const internalSpec = OpenApiDocumentFactory.generate(apiDocument, {
scope: 'internal',
});
Scope filtering is applied at the type-system level by OPRA's DataType.inScope() — it is the same mechanism used across the whole OPRA stack, not an OpenAPI-specific feature.