Skip to content

dhineshpandiyan/routing-controllers-openapi-extended

 
 

Repository files navigation

routing-controllers-openapi-extended

Build Status

Swagger v2 and OpenAPI v3 schema generation using beautiful typescript decorators.

Table of Contents

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

// 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.

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

{
  summary?: string;
  description?: string;
  operationId?: string;
  consumes?: Array<string>;
  produces?: Array<string>;
  security?: any;
}

Example

@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

{
  [key: string]: any;
}

Example

@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

Array<{
  lang: string;
  snippet: string;
}>

Example

@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

{
  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.

@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.

@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

{
  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.

@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' }] } } })

@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

{
	enabled: boolean,
}

Example

@Model() // This is enabled model
@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

{
	type?: Function;
	description?: string;
	name?: string;
	itemType?: Function;
	required?: boolean;
	example?: any;
	[key: string]: any;
}

Example

@Property({ description: 'Name of the user'})
@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

About

Runtime OpenAPI v3 schema generation for routing-controllers.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • TypeScript 99.2%
  • JavaScript 0.8%