Introduction
openapi-metadata
is a framework agnostic library to automatically generate OpenAPI schemas and documentation by using Typescript decorators and metadata.
import { ApiOperation, ApiResponse } from "openapi-metadata/decorators"; import User from "./user"; class UsersController { @ApiOperation({ methods: ["get"], path: "/users", summary: "List users" }) @ApiResponse({ type: [User] }) async list() { ... } }
import { ApiProperty } from "openapi-metadata/decorators"; class User { @ApiProperty() declare id: number; @ApiProperty() declare name: string; @ApiProperty({ required: false }) declare mobile?: string; }
import "reflect-metadata"; import { generateDocument } from "openapi-metadata"; import UsersController from "./users_controller"; const document = await generateDocument({ controllers: [UsersController], document: { info: { title: "My Api", version: "1.0.0", }, }, }); console.log(document); // <- Your generated OpenAPI specifications
- ✅ Fully compliant OpenAPI V3
- ✅ Automatic type inference
- ✅ Supports Scalar, Swagger UI and Rapidoc
- ✅ Extensible with custom type loaders
- ✅ Ready to be integrated with your favorite framework
Getting started
Setup
Install openapi-metadata
and reflect-metadata
using your favorite package manager.
npm install openapi-metadata reflect-metadata
Import reflect-metadata
in your main file.
import "reflect-metadata"; // Rest of your app
Enable emitDecoratorMetadata
and experimentalDecorators
.
{ "compilerOptions": { "emitDecoratorMetadata": true, "experimentalDecorators": true } }
Create your OpenAPI document
To get started, you can use the generateDocument
function to create an (almost) empty documentation. You can define a base document that will be merged with the generated one.
import "reflect-metadata"; import { generateDocument } from "openapi-metadata"; const document = await generateDocument({ controllers: [], document: { info: { title: "My API", version: "1.0.0", }, }, }); console.log(document); // <- Your generated OpenAPI specifications
Create your first controller
A controller is a simple class where each methods could be an Operation. In the following example we have a UsersController
which declares an operation GET /users
that returns a list of Users
.
import { ApiOperation, ApiResponse } from "openapi-metadata/decorators"; import User from "../schemas/user"; export default class UsersController { @ApiOperation({ methods: ["get"], path: "/users", summary: "List users", }) @ApiResponse({ type: [User] }) async list() { // ...your logic } }
Create your first schema
In our controller we define the response of your operation to be [User]
(a list of users). We now need to create this model.
By using the @ApiProperty
decorator on class we can define the properties of our schema.
Unlike other libraries like
@nestjs/swagger
, every element of your OpenAPI schema is lazy-loaded. Your models will only be part of your documentation if it is used.
import { ApiProperty } from "openapi-metadata/decorators"; export default class User { @ApiProperty() declare id: string; @ApiProperty({ example: "John Doe" }) declare name: string; @ApiProperty() declare email: string; @ApiProperty({ required: false }) declare mobile?: string; }
Register your controller
Now that we have our controller ready, we can include it when generating our document.
import "reflect-metadata"; import { generateDocument } from "openapi-metadata"; import UsersController from "./controllers/users_controller.ts"; const document = await generateDocument({ controllers: [UsersController], document: { info: { name: "My API", version: "1.0.0", }, }, }); console.log(document); // <- Your generated OpenAPI specifications