- Notifications
You must be signed in to change notification settings - Fork64
Runtime OpenAPI v3 schema generation for routing-controllers.
License
epiphone/routing-controllers-openapi
Folders and files
| Name | Name | Last commit message | Last commit date | |
|---|---|---|---|---|
Repository files navigation
Runtime OpenAPI v3 schema generation forrouting-controllers.
npm install --save routing-controllers-openapi
import{getMetadataArgsStorage}from'routing-controllers'import{routingControllersToSpec}from'routing-controllers-openapi'// Define your controllers as usual:@JsonController('/users')classUsersController{ @Get('/:userId')getUser(@Param('userId')userId:string){// ...} @HttpCode(201) @Post('/')createUser(@Body()body:CreateUserBody){// ...}}// Generate a schema:conststorage=getMetadataArgsStorage()constspec=routingControllersToSpec(storage)console.log(spec)
prints out the following specification:
{"components": {"schemas": {} },"info": {"title":"","version":"1.0.0" },"openapi":"3.0.0","paths": {"/users/{userId}": {"get": {"operationId":"UsersController.getUser","parameters": [ {"in":"path","name":"userId","required":true,"schema": {"type":"string" } } ],"responses": {"200": {"content": {"application/json": {} },"description":"Successful response" } },"summary":"List users","tags": ["Users"] } },"/users/": {"post": {"operationId":"UsersController.createUser","requestBody": {"content": {"application/json": {"schema": {"$ref":"#/components/schemas/CreateUserBody" } } },"description":"CreateUserBody","required":false },"responses": {"201": {"content": {"application/json": {} },"description":"Successful response" } },"summary":"Create user","tags": ["Users"] } } }}Check/sample for a complete sample application.
routingControllersToSpec has the following type signature:
exportfunctionroutingControllersToSpec(storage:MetadataArgsStorage,routingControllerOptions:RoutingControllersOptions={},additionalProperties:Partial<OpenAPIObject>={}):OpenAPIObject
routingControllerOptions refers to the options object used to configure routing-controllers. Pass in the same options here to have yourroutePrefix anddefaults options reflected in the resulting OpenAPI spec.
additionalProperties is a partialOpenAPI object that gets merged into the result spec. You can for example set your owninfo orcomponents keywords here.
Useclass-validator-jsonschema to convert your validation classes into OpenAPI-compatible schemas:
import{validationMetadatasToSchemas}from'class-validator-jsonschema'// ...constschemas=validationMetadatasToSchemas({refPointerPrefix:'#/components/schemas/',})constspec=routingControllersToSpec(storage,routingControllerOptions,{components:{ schemas},info:{title:'My app',version:'1.2.0'},})
Use the@OpenAPI decorator to supply your actions with additional keywords:
import{OpenAPI}from'routing-controllers-openapi'@JsonController('/users')exportclassUsersController{ @Get('/') @OpenAPI({description:'List all available users',responses:{'400':{description:'Bad request',},},})listUsers(){// ...}}
The parameter object consists of any number of properties from theOperation object. These properties are then merged into the spec, overwriting any existing values.
Alternatively you can call@OpenAPI with a function of type(source: OperationObject, route: IRoute) => OperationObject, i.e. a function receiving the existing spec as well as the target route, spitting out an updated spec. This function parameter can be used to implement for example your own merging logic or custom decorators.
A single handler can be decorated with multiple@OpenAPIs. Note though that since decorators are applied top-down, any possible duplicate keys are overwritten by subsequent decorators:
@OpenAPI({summary:'This value will be overwritten!',description:'This value will remain'}) @OpenAPI({summary:'This value will remain'})listUsers(){// ...}
Multiple@OpenAPIs are merged together withlodash/merge which hasa few interesting properties to keep in mind when it comes to arrays. Use the function parameter described above when strict control over merging logic is required.
Using@OpenAPI on the controller class effectively applies given spec to each class method. Method-level@OpenAPIs are merged into class specs, with the former having precedence:
@OpenAPI({security:[{basicAuth:[]}],// Applied to each method})@JsonController('/users')exportclassUsersController{// ...}
Extracting response types automatically in runtime isn't currently allowed by Typescript's reflection system. Specifically the problem is thatrouting-controllers-openapi can't unwrap generic types like Promise or Array: see e.g.here for discussion. As a workaround you can use the@ResponseSchema decorator to supply the response body schema:
import{ResponseSchema}from'routing-controllers-openapi'@JsonController('/users')exportclassUsersController{ @Get('/:id') @ResponseSchema(User)getUser(){// ...}}
@ResponseSchema takes as an argument either a class-validator class or a plain string schema name. You can also supply an optional secondaryoptions argument:
@Post('/') @ResponseSchema(User,{contentType:'text/csv',description:'A list of created user objects',isArray:truestatusCode:'201'})createUsers(){// ...}
contentType andstatusCode default to routing-controller's@ContentType and@HttpCode values. To specify a response schema of an array, setoptions.isArray astrue. You can also annotate a single handler with multipleResponseSchemas to specify responses with different status codes.
Note that when using@ResponseSchema together with@JSONSchema, the outer decorator will overwrite keys of inner decorators. So in the following example, information from@ResponseSchema would be overwritten by@JSONSchema:
@JSONSchema({responses:{'200':{'content':{'application/json':{schema:{'$ref':'#/components/schemas/Pet'}}}}}})@ResponseSchema(SomeResponseObject)handler(){ ...}
Multiple ResponseSchemas with different status codes are supported as follows.
@ResponseSchema(Response1)@ResponseSchema(Response2,{statusCode:'400'})
In case of multiple ResponseSchemas being registered with the same status code, we resolve themusing theoneOf operator.
@ResponseSchema(Response1)@ResponseSchema(Response2)
will generate
"200": {"content": {"application/json":{"schema": {"oneOf": [ {$ref: "#/components/schemas/Response1"}, {$ref: "#/components/schemas/Response2"} ] } } }}
@Controller/@JsonControllerbase route and default content-typeoptions.routePrefix@Get,@Postand other action decorators- Parse path parameters straight from path strings and optionally supplement with
@Paramdecorator- Regex and optional path parameters (e.g.
/users/:id(\d+)/:type?) are also supported
- Regex and optional path parameters (e.g.
@QueryParamand@QueryParams@HeaderParamand@HeaderParams@Bodyand@BodyParam- Parse response keywords from
@HttpCodeand@ContentTypevalues - Global
options.defaults.paramOptions.requiredoption and local override with{required: true}in decorator params - Parse
summary,operationIdandtagskeywords from controller/method names
- Support for routing-controller'sauthorization features
Feel free to submit a PR!
- Inspired bytsoa andtrafficlight
- Include your Mongoose models in the spec withmongoose-schema-jsonschema
- Generate JSON schema from your Typescript sources withtypescript-json-schema
- openapi3-ts provides handy OpenAPI utilities for Typescript
- Convert OpenAPI 3 spec toSwagger 2 withapi-spec-converter
- Generate Typescript interface definitions from SQL database schema withschemats
About
Runtime OpenAPI v3 schema generation for routing-controllers.
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Packages0
Uh oh!
There was an error while loading.Please reload this page.
Contributors14
Uh oh!
There was an error while loading.Please reload this page.