Swagger v2 and OpenAPI v3 schema generation using beautiful typescript decorators.
- About
- Installation
- Usage
- Available API's
- Available Decorators
- Next goals
- References
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.
npm i routing-controllers-openapi-extended
// 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:
{
"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
for a complete sample application.
This API will be used to generate swagger 2.0 specifications.
This API will be used to generate Open API 3.0 configurations.
This is used to specify most of the basic information about each operations.
summary
[String
] - used to specify summary information about operationdescription
[String
] - used to specify description information about operationoperationId
[String
] - used to specify / override operation id about operationconsumes
[Array<string>
] - used to specify consumer listproduces
[Array<string>
] - used to specify produces listsecurity
[any
] - allow user to define their own security specification
{
summary?: string;
description?: string;
operationId?: string;
consumes?: Array<string>;
produces?: Array<string>;
security?: any;
}
@OperationInfo({ summary: '<summary info>', description: '<detailed info>', operationId: '<unique operation id>' })
This is used to add all custom properties which may/ may not be specified in swagger sepcification.
<any key name>
[any
] - entire object will be attached to the specific operation
{
[key: string]: any;
}
@CustomEntry({ customField: '<values>', 'x-status': '<status>' })
This is another kind of custom entry which can be attached to operation sepcification.
lang
[String
] - used to specify languagesnippet
[String
] - used to specify sample code
Array<{
lang: string;
snippet: string;
}>
@CodeSnippets([{ lang: '<language>', snippet: '<code snippet>' }])
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).
name
[String
] - used to specify namein
[String
] - used to specify type of parameterdescription
[String
] - used to specify descriptiontype
[String
] - used to data type of the parameterrequired
[Boolean
] - used to required flagschema
[Object
] - used to specify schema of the data typeexamples
[Object
] - used to specify examplesexample
[any
] - used to specify sample exampledefault
[any
] - used to specify default valueformat
[any
] - used to specify format value (like int64)<any key name>
[any
] - entire object will be attached to the specific operation
{
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;
};
Users shall attach additinal parameters to the existing operation.
@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 bebody
for@Body
type paramters.
@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 }
}
This is used to add responses
entry with proper status code and samples to the operation.
statusCode
[Number
orString
] - used to specify namedescription
[String
] - used to specify descriptiontype
[String
] - used to data type of the parameterschema
[Function
orString
] - used to specify schema of the data typeexamples
[Object
] - used to specify examplesheaders
[Object
] - used to specify examples<any key name>
[any
] - entire object will be attached to the specific operation
{
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;
};
Users shall attach responses to the operation.
@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.
@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' }] } } })
This is used to specify model schema which will be considered for schema definition generation.
enabled
[Boolean
] - used to specify include/ exclude from schema definition generation.Default: true
{
enabled: boolean,
}
@Model() // This is enabled model
@Model({ enabled: true })
This is used to specify the property which is included in the schema definition generation.
type
[Function
] - Used to specify explicit type, By default this will get the declared typedescription
[String
] - Used to specify description of the propertyname
[String
] - Used to specify explicit name of the property, By default this will get the property nameitemType
[Function
] - Used to specify item data type if it is an array. This is mandatory property if the property type isArray
required
[Boolean
] - Used to specify whether it is required property or notexample
[any
] - Used to specify an example value<any key>
[any
] - Used to specify custom properties which needs to attach with property definiiton
{
type?: Function;
description?: string;
name?: string;
itemType?: Function;
required?: boolean;
example?: any;
[key: string]: any;
}
@Property({ description: 'Name of the user'})
@Property({ itemType: String, description: 'List of user hobbies' })
- Implement Operation decorator to use without routing-controller decorators
- Refactor code to sperate two different data sources
- Implement logging to troubleshot generaiton operation