Skip to main content

OpenAPI Integration

OPRA's type system is intentionally richer than OpenAPI's schema model. Several concepts that OPRA supports natively have no direct equivalent in OpenAPI 3.x:

  • Type inheritance and extension — OPRA types can extend a base ComplexType; OpenAPI has no native inheritance construct.
  • MixinType — merges multiple types into one at the field level, with no OpenAPI parallel.
  • MappedType transforms — PickType, OmitType, PartialType, RequiredType produce derived types at the schema level; OpenAPI has no equivalent transform primitives.
  • UnionType with discriminator — maps to oneOf, but OPRA's discriminator is enforced at runtime with validation logic that OpenAPI cannot express.
  • SEARCH and QUERY methods — OPRA supports these emerging HTTP methods; OpenAPI 3.x's path item spec does not.
  • Scope-filtered fields — individual fields and parameters can be hidden per audience (public / internal / admin) at the type-system level; OpenAPI has no built-in equivalent.
  • ArrayType with minOccurs/maxOccurs — OPRA's typed array wrapper carries occurrence constraints that go beyond what OpenAPI's items schema conveys.

Despite these gaps, OpenAPI is a widely adopted industry standard. Tooling ecosystems — Swagger UI, Postman, Scalar, API gateways, client generators — all speak OpenAPI. To make OPRA services compatible with this ecosystem, @opra/openapi provides a best-effort conversion: OPRA constructs that map cleanly are converted faithfully; those that have no OpenAPI equivalent are approximated or skipped, with a warning recorded for each.


@opra/openapi generates standard OpenAPI 3.0 / 3.1 documents from an OPRA ApiDocument. Once you have an ApiDocument — the runtime representation of your OPRA HTTP service — this package converts it to a spec-compliant JSON object you can serve with Swagger UI, import into Postman, feed to API gateways, or use with any OpenAPI-aware tooling.


Installation​

npm install @opra/openapi

@opra/common is a peer dependency; install it too if you haven't already.


How it works​

OPRA's ApiDocument already contains everything needed: controllers, operations, typed request/response shapes, parameters, and the data type registry. @opra/openapi walks this structure and maps each piece to its OpenAPI equivalent:

OPRA constructOpenAPI equivalent
HttpControllerPath items (grouped by URL)
HttpOperationOperation object (get, post, … under each path)
.QueryParam(), .PathParam(), .Header(), .Cookie()parameters[]
.RequestContent()requestBody
.Response()responses
ComplexType / MappedType / MixinTypecomponents.schemas object
EnumTypecomponents.schemas {type:"string", enum:[...]}
ArrayType{type:"array", items:...}
UnionType{oneOf:[...]}
SimpleTypeInlined primitive schema (string, integer, boolean, …)

Named model types (ComplexType, EnumType, UnionType, ArrayType) are placed in components.schemas and referenced with $ref. Simple types are always inlined.


Quick example​

import { ApiDocumentFactory, OpraSchema } from '@opra/common';
import { OpenApiDocumentFactory } from '@opra/openapi';

// Build (or obtain) your ApiDocument
const apiDocument = await ApiDocumentFactory.createDocument({ ... });

// Generate an OpenAPI 3.0 document
const openApiDoc = OpenApiDocumentFactory.generate(apiDocument);

// openApiDoc is a plain JSON-serialisable object — serve or write it
console.log(JSON.stringify(openApiDoc, null, 2));

→ Generating Documents