routing-controllers-openapi-extended
Version:
Runtime Swagger v2 / OpenAPI v2 specification generation for routing-controllers
488 lines (414 loc) • 15.3 kB
Markdown
# routing-controllers-openapi-extended
[](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)