UNPKG

routing-controllers-openapi-extended

Version:

Runtime Swagger v2 / OpenAPI v2 specification generation for routing-controllers

488 lines (414 loc) 15.3 kB
# routing-controllers-openapi-extended [![Build Status](https://travis-ci.com/dhineshpandiyan/routing-controllers-openapi-extended.svg?branch=master)](https://travis-ci.org/dhineshpandiyan/routing-controllers-openapi-extended) Swagger v2 and OpenAPI v3 schema generation using beautiful typescript decorators. ## Table of Contents - [About](#about) - [Installation](#installation) - [Usage](#usage) - [Available API's](#available-apis) - [.generateSwagger({ controllers, models, storage }, additional)](#generateswagger-controllers-models-storage--additional) - [.generateOpenAPI(storage, options, validationMetadata, additional)](#generateopenapi-controllers-models-storage--additional) - [Available Decorators](#available-decorators) - [@OperationInfo(options)](#operationinfooptions) - [@Available Options](#available-options) - [@Syntax](#syntax) - [@Example](#example) - [@CustomEntry(options)](#customentryoptions) - [@Available Options](#available-options) - [@Syntax](#syntax) - [@Example](#example) - [@CodeSnippets(options)](#codesnippetsoptions) - [@Available Options](#available-options) - [@Syntax](#syntax) - [@Example](#example) - [@Parameters(options)](#parametersoptions) - [@Available Options](#available-options) - [@Syntax](#syntax) - [@Example](#example) - [@ResponseEntry(options)](#responseentryoptions) - [@Available Options](#available-options) - [@Syntax](#syntax) - [@Example](#example) - [@Model(options)](#modeloptions) - [@Available Options](#available-options) - [@Syntax](#syntax) - [@Example](#example) - [@Property(options)](#propertyoptions) - [@Available Options](#available-options) - [@Syntax](#syntax) - [@Example](#example) - [Next goals](#next-goals) - [References](#references) ## About This node module will extract much information about operations, parameters, responses from `routing-controller` decorator methods. Additinally it provides some more typescript decorators which will be useful to add user defined custom properties to the generated swagger specification. This library uses `class-validator` decorator to generate schema definitions currently. ## Installation `npm i routing-controllers-openapi-extended` ## Usage ```typescript // UserController.ts import { Body, Get, JsonController, Param, Post } from 'routing-controllers' import { OperationInfo, ResponseEntry, Parameters, Model, Property } from 'routing-controllers-openapi-extended'; @Model() export class CreateUserBody { @Property({ description: 'Name of the user'}) name: string @Property({ itemType: String, description: 'List of user hobbies' }) hobbies: string[] } @JsonController('/users') export class UsersController { @Get('/:id') @OperationInfo({ summary: 'Get user by Id', description: 'Get user by Id' }) @ResponseEntry({ statusCode: 200, schema: CreateUserBody, description: 'Retrived user by the supplied user id', examples: { 'applications/json': { userId: '<sample data>' } } }) getOne(@Param('id') id: number) { return { name: 'User #' + id } } @Post('/:id') @Parameters([ { name: 'Authorization', in: 'header', type: 'string', description: 'Used to attached token', required: true, default: 'Basic <token>' }, { name: 'body', description: 'Detailed information about creat user body', required: true }, { name: 'id', description: 'Detailed information about id parameter' }, ]) @ResponseEntry({ statusCode: 200, schema: CreateUserBody, description: 'Information about created user', examples: { 'applications/json': { userId: '<sample data>' } } }) createUser(@Body() body: CreateUserBody, @Param('id') id: string) { return { ...body, id: 3 } } } // SchemaGenerator.ts: import 'reflect-metadata' import { getMetadataArgsStorage } from 'routing-controllers' import { generateSwagger } from 'routing-controllers-openapi-extended' import { UsersController, CreateUserBody } from './UsersController' const spec = generateSwagger({ controllers: [UsersController], models: [CreateUserBody], storage: getMetadataArgsStorage(), }, { info: { description: 'Generated by script', title: 'A sample API', version: '1.0.0' } }); console.log(JSON.stringify(spec, undefined, 2)); ``` This will generate below swagger v2 specification: ```json { "swagger": "2.0", "paths": { "/users/{id}": { "get": { "operationId": "UsersController.getOne", "summary": "Get user by Id", "tags": [ "Users" ], "parameters": [ { "in": "path", "name": "id", "required": true, "type": "string" } ], "responses": { "200": { "description": "Retrived user by the supplied user id", "examples": { "applications/json": { "userId": "<sample data>" } }, "schema": { "$ref": "#/definitions/CreateUserBody" } } }, "description": "Get user by Id" }, "post": { "operationId": "UsersController.createUser", "summary": "Create user", "tags": [ "Users" ], "parameters": [ { "in": "path", "name": "id", "required": true, "type": "string", "description": "Detailed information about id parameter" }, { "in": "body", "name": "body", "required": true, "schema": { "$ref": "#/definitions/CreateUserBody" }, "description": "Detailed information about creat user body" }, { "name": "Authorization", "in": "header", "type": "string", "description": "Used to attached token", "required": true, "default": "Basic <token>" } ], "responses": { "200": { "description": "Information about created user", "examples": { "applications/json": { "userId": "<sample data>" } }, "schema": { "$ref": "#/definitions/CreateUserBody" } } } } } }, "definitions": { "CreateUserBody": { "type": "object", "required": [ "name", "hobbies" ], "properties": { "name": { "type": "string", "description": "Name of the user" }, "hobbies": { "type": "array", "description": "List of user hobbies", "items": { "type": "string" } } } } }, "info": { "description": "Generated by script", "title": "A sample API", "version": "1.0.0" } } ``` Check [`/sample`](/sample) for a complete sample application. ## Available API's ### .generateSwagger({ controllers, models, storage }, additional) This API will be used to generate swagger 2.0 specifications. ### .generateOpenAPI({ controllers, models, storage }, additional) This API will be used to generate Open API 3.0 configurations. ## Available Decorators ### @OperationInfo(options) This is used to specify most of the basic information about each operations. #### Available Options - `summary` [`String`] - used to specify summary information about operation - `description` [`String`] - used to specify description information about operation - `operationId` [`String`] - used to specify / override operation id about operation - `consumes` [`Array<string>`] - used to specify consumer list - `produces` [`Array<string>`] - used to specify produces list - `security` [`any`] - allow user to define their own security specification #### Syntax ```typescript { summary?: string; description?: string; operationId?: string; consumes?: Array<string>; produces?: Array<string>; security?: any; } ``` #### Example ```typescript @OperationInfo({ summary: '<summary info>', description: '<detailed info>', operationId: '<unique operation id>' }) ``` ### @CustomEntry(options) This is used to add all custom properties which may/ may not be specified in swagger sepcification. #### Available Options - `<any key name>` [`any`] - entire object will be attached to the specific operation #### Syntax ```typescript { [key: string]: any; } ``` #### Example ```typescript @CustomEntry({ customField: '<values>', 'x-status': '<status>' }) ``` ### @CodeSnippets(options) This is another kind of custom entry which can be attached to operation sepcification. #### Available Options - `lang` [`String`] - used to specify language - `snippet` [`String`] - used to specify sample code #### Syntax ```typescript Array<{ lang: string; snippet: string; }> ``` #### Example ```typescript @CodeSnippets([{ lang: '<language>', snippet: '<code snippet>' }]) ``` ### @Parameters(options) This is used to add additional properties to the existing parameter (including query parameter and body parameters). And allow user to attach any header parameters (like pagination, content-type etc). #### Available Options - `name` [`String`] - used to specify name - `in` [`String`] - used to specify type of parameter - `description` [`String`] - used to specify description - `type` [`String`] - used to data type of the parameter - `required` [`Boolean`] - used to required flag - `schema` [`Object`] - used to specify schema of the data type - `examples` [`Object`] - used to specify examples - `example` [`any`] - used to specify sample example - `default` [`any`] - used to specify default value - `format` [`any`] - used to specify format value (like int64) - `<any key name>` [`any`] - entire object will be attached to the specific operation #### Syntax ```typescript { name: string; in?: 'query' | 'header' | 'path' | 'body' | 'cookie'; description?: string; type?: string; required?: boolean; deprecated?: boolean; schema?: { $ref: string }; examples?: { [key: string]: any; }; example?: any; default?: any; format?: any; [key: string]: any; }; ``` #### Example Users shall attach additinal parameters to the existing operation. ```typescript @Parameters({ name: 'Authorization', in: 'header', type: 'string', description: 'Used to attached token' required: true, default: 'Basic <token>'}) ``` User shall use the same Parameters decorator to override/ amend existing paramters. > `name` value should match with the `@Param` `name` for query and path parameter entiries. > `name` value should be `body` for `@Body` type paramters. ```typescript @Post('/:id') @Parameters([{ name: 'Authorization', in: 'header', type: 'string', description: 'Used to attached token' required: true, default: 'Basic <token>'}]) @Parameters([ { name: 'body', description: 'Detailed information about creat user body', required: true } ]) @Parameters([ { name: 'id', description: 'Detailed information about id parameter'} ]) createUser(@Body() reqBody: CreateUserBody, @Param('id') id: string) { return { ...body, id: 3 } } ``` ### @ResponseEntry(options) This is used to add `responses` entry with proper status code and samples to the operation. #### Available Options - `statusCode` [`Number` or `String`] - used to specify name - `description` [`String`] - used to specify description - `type` [`String`] - used to data type of the parameter - `schema` [`Function` or `String`] - used to specify schema of the data type - `examples` [`Object`] - used to specify examples - `headers` [`Object`] - used to specify examples - `<any key name>` [`any`] - entire object will be attached to the specific operation #### Syntax ```typescript { statusCode: number | string, description?: string; type?: string; schema?: Function | string, examples?: { [key: string]: any; }; example?: any; headers?: { [name: string]: { type: string; description?: string; [key: string]: any; }; }; [key: string]: any; }; ``` #### Example Users shall attach responses to the operation. ```typescript @ResponseEntry({ statusCode: 200, schema: CreateUserBody, description: 'detailed information about the response' }) ``` User shall add more information along with responses like examples, header information. Users shall add more than one responses to the operations. ```typescript @ResponseEntry({ statusCode: 200, schema: CreateUserBody, description: 'detailed information about the response', examples: { 'applications/json': { userId: '<sample data>' } } }) @ResponseEntry({ statusCode: 404, schema: ErrorResponse, description: 'details about the error response', examples: { 'applications/json': { erros: [ { message: 'sample error message' }] } } }) ``` ### @Model(options) This is used to specify model schema which will be considered for schema definition generation. #### Available Options - `enabled` [`Boolean`] - used to specify include/ exclude from schema definition generation. `Default: true` #### Syntax ```typescript { enabled: boolean, } ``` #### Example ```typescript @Model() // This is enabled model ``` ```typescript @Model({ enabled: true }) ``` ### @Property(options) This is used to specify the property which is included in the schema definition generation. #### Available Options - `type` [`Function`] - Used to specify explicit type, By default this will get the declared type - `description` [`String`] - Used to specify description of the property - `name` [`String`] - Used to specify explicit name of the property, By default this will get the property name - `itemType` [`Function`] - Used to specify item data type if it is an array. This is mandatory property if the property type is `Array` - `required` [`Boolean`] - Used to specify whether it is required property or not - `example` [`any`] - Used to specify an example value - `<any key>` [`any`] - Used to specify custom properties which needs to attach with property definiiton #### Syntax ```typescript { type?: Function; description?: string; name?: string; itemType?: Function; required?: boolean; example?: any; [key: string]: any; } ``` #### Example ```typescript @Property({ description: 'Name of the user'}) ``` ```typescript @Property({ itemType: String, description: 'List of user hobbies' }) ``` ## Next goals - Implement Operation decorator to use without routing-controller decorators - Refactor code to sperate two different data sources - Implement logging to troubleshot generaiton operation ## References - [routing-controllers](https://github.com/typestack/routing-controllers)