sails-hook-swagger-generator v3.3.0
Swagger Generator Sails Hook
This helps to create swagger documentation json which is based entirely on Swagger/OpenAPI specification (see here). The hook produces specification based upon OAS 3.0.

Installation
$ npm install sails-hook-swagger-generator --saveDemo
Copy the content of generatedSwagger and paste it in Swagger Online Editor.
Usage
Simply by lifting your sails app sails lift, after lifting or starting the app,there should be swagger.json within ./swagger folder.
make sure ./swagger folder is already existing.
Check the ./swagger/swagger.json for generated swagger documentation json, then head to Swagger Editor.
Generated Output
By default, the Swagger Generator Sails Hook generates:
1. Full automatic documentation for all Sails Blueprint routes;
1. Documentation for all Sails
actions2
actions with routes configured in config/routes.js; and
1. Listing of all routes configured in config/routes.js (full details cannot be inferred
for custom routes without additional information being provided - see below).
1. Creation of default tags for paths based upon Sails Model and Controller globalId's.
Use with Swagger UI
See #28
Adding/Customising Generated Output
Documentation detail and customisation of most aspects of the generated Swagger can be achieved by adding:
1. Top-level configuration to config/swaggergenerator.js. This provides direct JSON
used as the template for the output Swagger/OpenAPI.
1. Objects with the key swagger to custom route configuration, controller files, action
functions, model definitions and model attribute definitions. The swagger element must be of type
SwaggerActionAttribute for actions (based on OpenApi.Operation)
or SwaggerModelSchemaAttribute for model schemas (based on OpenApi.UpdatedSchema).
1. JSDoc (swagger-jsdoc) @swagger comments
to controller/action files and model files.
Top-level Swagger/OpenAPI definitions for tags and components may be added in all swagger objects
above and in all JSDoc @swagger documentation comments. This enables the definition of top-level elements.
See below for details.
Configurations
It comes with some default settings which can be overridden by creating config/swaggergenerator.js:
module.exports['swagger-generator'] = {
disabled: false,
swaggerJsonPath: './swagger/swagger.json',
swagger: {
openapi: '3.0.0',
info: {
title: 'Swagger Json',
description: 'This is a generated swagger json for your sails project',
termsOfService: 'http://example.com/terms',
contact: {name: 'Theophilus Omoregbee', url: 'http://github.com/theo4u', email: 'theo4u@ymail.com'},
license: {name: 'Apache 2.0', url: 'http://www.apache.org/licenses/LICENSE-2.0.html'},
version: '1.0.0'
},
servers: [
{ url: 'http://localhost:1337/' }
],
externalDocs: {url: 'http://theophilus.ziippii.com'}
},
defaults: {
responses: {
'200': { description: 'The requested resource' },
'404': { description: 'Resource not found' },
'500': { description: 'Internal server error' }
}
},
excludeDeprecatedPutBlueprintRoutes: true,
includeRoute: function(routeInfo) { return true; },
updateBlueprintActionTemplates: function(blueprintActionTemplates) { ... },
postProcess: function(specifications) { ... }
};Notes on the use of configuration:
disabledattribute is used to disable the module (e.g you may want to disable it on production).swaggerJsonPathwhere to generate theswagger.jsonfile to; defaults tosails.config.appPath + '/swagger/swagger.json'and output file will not be written if empty/null/undefined (seepostProcessbelow for alternate save mechanism).swaggerobject is template for the Swagger/OpenAPI output. It defaults to the minimal content above. Check Swagger/OpenAPI specification for more, in case you want to extend it. Generally, this hook provides sensible defaults for as much as possible but you may override them in this location or in any of the mechanisms explained below.defaultsobject should contain theresponseselement; defaults to the above if not specified.excludeDeprecatedPutBlueprintRoutesshould deprecatedPUTblueprint routes be excluded from generated Swagger output; defaults totrue.includeRoutefunction used to filter routes to be included in generated Swagger output; see advanced section below.updateBlueprintActionTemplatesallows customisation of the templates used to generate Swagger for blueprints; see advanced section below.postProcessallows an alternate mechanism for saving and/or modification of the generated Swagger output before it is written to the output file; see advanced section below.
Custom Route Configuration
Documentation detail and customisation of most aspects of the generated Swagger for custom routes may be achieved by:
- Adding an object with the key
swagger(must be of type SwaggerActionAttribute for actions, based on OpenApi.Operation) to individual route configurations inconfig/routes.js. - Adding an object with the key
swagger(must be of type SwaggerControllerAttribute) to the exports of a controller file, standalone action file or actions2 file. - Adding an object with the key
swagger(must be of type SwaggerModelAttribute) to the exports of a model file. - Adding JSDoc
@swaggercomments to Sails model files, controller files, standalone action files or actions2 files; specifically:- JSDoc
@swaggerdocumentation under the/{actionName}path for the route (controllers/actions), or - JSDoc
@swaggerdocumentation under the/{blueprintAction}path for the route (models), or - JSDoc
@swaggerdocumentation undertagsandcomponentspaths for adding to the top-level Swagger/OpenAPI definitions.
- JSDoc
Custom Route Configuration in config/routes.js
If you want to add extra configuration to a route, it can be done via the config/routes.js, since Sails uses different route targets, we can leverage the route object target to extend/override our swagger configuration by adding an object with a key swagger.
For example, in config/routes.js:
{
'post /user/login': {
controller: 'UserController',
action: 'login',
swagger: {
summary: 'Authentication',
description: 'This is for authentication of any user',
tags: [ 'Tag Name' ],
requestBody: {
content: {
'application/json': {
schema: {
properties: {
email: { type: 'string' },
password: { type: 'string', format: 'password' }
},
required: [ 'email', 'password' ],
}
}
}
},
parameters: [{
in: 'query',
name: 'firstName',
required: true,
schema: { type: 'string' },
description: 'This is a custom required parameter'
}],
responses: {
'200': {
description: 'The requested resource',
content: {
'application/json': {
schema: {
type: 'array',
items: { '$ref': '#/components/schemas/someDataType' },
},
},
},
},
'404': { description: 'Resource not found' },
'500': { description: 'Internal server error' }
}
}
}
}Custom Route Configuration in Controller or Action files
Documentation detail and customisation of most aspects of the generated Swagger may be added to controller files, standalone action files or actions2 files as follows:
- Adding an object with the key
swaggeradded to a controller file action function. - Adding an object with the key
swaggerto the exports of a controller file, standalone action file or actions2 file:- For controller files, actions are referenced by adding objects keyed on
swagger.actions.{actionName}name. See UserController.js; - For standalone action or actions2 files, placing content in the
swagger.actions.{actionFileName|actions2FileName}object. See actions2.js *Note:actionFileName|actions2FileNamemust correspond to the filename*; - For all controller/action files, adding per-action documentation to be
applied to all actions using the key
swagger.actions.allActionse.g. use this to apply common tags to all actions for a controller. - Adding documentation under
tagsandcomponentselements for adding to the top-level Swagger/OpenAPI definitions. See example in either UserController.js or actions2.js.
- For controller files, actions are referenced by adding objects keyed on
- Adding JSDoc
@swaggercomments to controller file, standalone action file or actions2 file:- JSDoc
@swaggerdocumentation under the/{actionName}path for the controller file actions, - JSDoc
@swaggerdocumentation under the/{actionFileName|actions2FileName}path for standalone action or actions2 files, - JSDoc
@swaggerdocumentation under the/allActionspath to be applied to all actions for the controller, or - JSDoc
@swaggerdocumentation undertagsandcomponentspaths for adding to the top-level Swagger/OpenAPI definitions.
- JSDoc
An exclude property, set to true, may be added to any swagger element or @swagger JSDoc
action documentation to exclude that action from the generated Swagger. See example in
NomodelController.js.
The Swagger definition for each action is merged in the order above to form the final
definition, with config/routes.js taking highest precendence and earlier definitions
above taking precedence over later.
For actions2 files:
- Inputs are parsed to generate parameter documentation.
- Exits are parsed to generate response documentation.
- Both may be customised/overridden by specifying parameters and/or responses in the
swaggerobject in actions2 file. - Inputs may also add an object with the key
meta.swaggerto document the attributes Swagger/OpenAPI schema associated with the input value. See example in actions2.js. - Inputs may be excluded from the generated Swagger by setting
meta.swagger.excludetotrue. - Inputs may specify where the input should be included within the generated Swagger using the key
meta.swagger.in. The valuesquery/header/path/cookiemay be used to produce Swagger operation parameters and the valuebodymay be used to producerequestBodyschema properties (valid for PUT/POST/PATCH operations only).
For example, for a route configured as:
module.exports.routes = {
'/api/v1/auth/tokens': 'AuthController.tokens',
};The tokens action might be documented in a Controller api/controllers/AuthController.js as follows:
function tokens(req, res) {
...
}
module.exports = {
tokens: tokens,
swagger: {
actions: {
tokens: {
tags: [ 'Auth' ],
description: 'Route description...'
}
}
tags: [
{
name: 'Auth',
description: 'Module description ...',
}
],
components: {
...
}
}
};Or, alternately using JSDoc:
/**
* @swagger
*
* /tokens:
* description: Route description...
* tags:
* - Auth
* tags:
* - name: Auth
* description: Module description...
*/
function tokens(req, res) {
...
}
module.exports = {
tokens: tokens
};Blueprint Route Configuration
Documentation detail and customisation of most aspects of the generated Swagger for blueprint routes may be achieved by:
- Adding an object with the key
swaggerto individual models e.g.api/models/modelName.js:- Adding documentation to the model's Swagger schema using the key
swagger.modelSchemae.g. use this to apply detailed documentation via thedescriptionfield; - In additon to the model's schema, the key
swagger.modelSchemamay be used to specify tag names (as astring[]) to be assigned all blueprint actions for the model. This is a non-standard convenience function i.e. in Swagger/OpenAPI you need to explicitly add tags to each/every OpenAPI.Operation; - Adding per-action documentation by adding objects keyed on
swagger.actions.{blueprintAction}name; - Adding action documentation to all actions using the key
swagger.actions.allActionse.g. use this to apply commonexternalDocsto all blueprint actions for the model; or - Adding documentation under
swagger.tagsandswagger.componentselements for adding to the top-level Swagger/OpenAPI definitions.
- Adding documentation to the model's Swagger schema using the key
- Adding documentation-specific fields to model attributes (supports
description,moreInfoUrlandexample). Note that applicable Sails attributes, automigrations and validations are also parsed. - Adding an object with the key
meta.swaggerto individual model attributes to document the attributes Swagger/OpenAPI schema. See example in Pet.js. - Adding JSDoc
@swaggercomments to model files:- JSDoc
@swaggerdocumentation under the/{globalId}to add documentation to the model's Swagger schema (or tags as noted above), - JSDoc
@swaggerdocumentation under the/{blueprintAction}to add per-action documentation for the model blueprint actions, - JSDoc
@swaggerdocumentation under the/allActionspath to be applied to all blueprint actions for the model, or - JSDoc
@swaggerdocumentation undertagsandcomponentspaths for adding to the top-level Swagger/OpenAPI definitions.
- JSDoc
An exclude property, set to true, may be added to any swagger element of @swagger JSDoc
action documentation to exclude the model completely (exclude the schema) or a specific
blueprint action from the generated Swagger. See example in OldPet.js.
Individual model attributes may be excluded from the generated Swagger by setting
meta.swagger.exclude to true. See example in Pet.js.
OpenAPI 3 specifies the Any Type by the absence of the type property in a schema;
this may be achieved by setting a model attribute's meta.swagger.type value to null.
See example in User.js.
The Swagger definition for each action is merged in the order above to form the final
definition, with config/routes.js taking highest precendence and earlier definitions
above taking precedence over later.
For example, in a model api/models/User.js:
/**
* @swagger
*
* /User:
* tags:
* - Tag Name
* /findone:
* externalDocs:
* url: https://docs.com/here
*/
module.exports = {
attributes: {
uid: {
type: 'string',
example: '012345',
description: 'A unique identifier',
}
},
swagger: {
actions: {
create: { ... },
},
modelSchema: { ... },
tags: [...]
components: {...}
}
};Note that following parameters are added to the components/parameters if they are not
provided in config/swaggergenerator.js (expressed as OpenAPI references):
[
{ $ref: '#/components/parameters/WhereQueryParam' },
{ $ref: '#/components/parameters/LimitQueryParam' },
{ $ref: '#/components/parameters/SkipQueryParam' },
{ $ref: '#/components/parameters/SortQueryParam' },
{ $ref: '#/components/parameters/SelectQueryParam' },
{ $ref: '#/components/parameters/PopulateQueryParam' },
]Note that when generating Swagger/OpenAPI documentation for blueprint routes, the hook also generates:
- Schemas for models, which may be referenced using the form
{ $ref: '#/components/schemas/modelName' }. - Parameters for model primary keys, which may be referenced using the form
{ $ref: '#/components/parameters/ModelPKParam-modelName' }.
These may be re-used (referenced) if/as applicable within custom route documentation.
Handling Top-Level Swagger Defintions (Tags and Components)
You are able to add to the top-level Swagger/OpenAPI definitions for tags and components in all swagger objects
detailed above and in all JSDoc @swagger documention comments.
All swagger objects may contain the elements tags and components(except the ones specified in `config.routes.js) e.g.
{
tags: [
{
name: 'Test Module',
description: 'Module description ...',
externalDocs: { url: 'https://docs.com/test' }
}
],
components: {
schemas: {
test: { ... }
}
}
}Similarly, JSDoc @swagger tags may define tags and components:
/**
* @swagger
*
* tags:
* - name: Test Module
* description: |
* Module description
* (continued).
*
* Another paragraph.
*
* externalDocs:
* url: https://docs.com/test
* description: Refer to these docs
*
* components:
* schemas:
* test:
* ...
*/Tags Handling
Tags are added to the top-level Swagger/OpenAPI definitions as follows:
1. If a tags with the specified name does not exist, it is added.
1. Where a tag with the specified name does exist, elements of that tag that do not exist are added
e.g. description and externalDocs elements.
Note that a final clean-up phase is run after processing, which performs the following: 1. Removal of unreferenced tags; and 2. Creation of tags referenced but are not defined.
Component Element Handling
Elements of components are added to the top-level Swagger/OpenAPI definitions as follows: 1. Elements of the component definition reference (schemas, parameters, etc) are added where they do not exist. 1. Existing elements are not overwritten or merged.
For example, the element components.schemas.pet will be added as part of a merge process,
but the contents of multiple definitions of pet will not be merged.
The following elements (from the OpenAPI 3 specification) are handled:
let componentDefinitionReference = {
// Reusable schemas (data models)
schemas: {},
// Reusable path, query, header and cookie parameters
parameters: {},
// Security scheme definitions (see Authentication)
securitySchemes: {},
// Reusable request bodies
requestBodies: {},
// Reusable responses, such as 401 Unauthorized or 400 Bad Request
responses: {},
// Reusable response headers
headers: {},
// Reusable examples
examples: {},
// Reusable links
links: {},
// Reusable callbacks
callbacks: {},
};Advanced Filtering/Processing of Generated Swagger
Three mechanisms are provided to enable advancing filtering of the Swagger generation process:
1. An includeRoute() function used to filter routes to be included in generated Swagger output.
1. An updateBlueprintActionTemplates() function allows customisation of the templates used to generate Swagger for blueprints.
1. A postProcess() function allows an alternate mechanism for saving and/or modification of the generated Swagger output before it is written to the output file.
Each is configured in config/swaggergenerator.js.
Route Information
This hook parses all routes, custom and blueprint, before commencing the generation of the Swagger output.
Each route is described by a SwaggerRouteInfo object
(see defintion here):
export interface SwaggerRouteInfo {
middlewareType: MiddlewareType; //< one of action|blueprint
verb: HTTPMethodVerb; //< one of all|get|post|put|patch|delete
path: string; //< full Sails URL as per sails.getUrlFor() including prefix
variables: string[]; //< list of ALL variables extracted from path e.g. `/pet/:id` --> `id`
optionalVariables: string[]; //< list of optional variables from path e.g. `/pet/:id?`
action: string; //< either blueprint action (e.g. 'find') or action identity (e.g. 'subdir/reporting/run')
actionType: ActionType; //< one of blueprint|shortcutBlueprint|controller|standalone|actions2|function
actions2Machine?: Sails.Actions2Machine; //< for actionType === 'actions2', details of the action2 machine
model?: SwaggerSailsModel; //< reference to Sails Model (blueprints only)
associationAliases?: string[]; //< association attribute names (relevant blueprint routes only)
defaultTagName?: string; //< default tag name for route, if any, based on Sails Model or Controller
swagger?: SwaggerActionAttribute; //< per-route Swagger (OpenApi Operation)
}Other interfaces for models, swagger elements etc may be found in interfaces.ts.
Route Filtering
The includeRoute(routeInfo): boolean function may be used to select which routes are included in the generated Swagger output.
For example:
module.exports['swagger-generator'] = {
includeRoute: (routeInfo) => {
let c = routeInfo.controller;
if(!c) return true;
if(c.toLowerCase().startsWith('user')) return true;
return false;
}
}Customising Blueprint Action Templates
The templates used for generating Swagger for each Sails blueprint action route may be
customised / modified / added to using the updateBlueprintActionTemplates config option
e.g. to support custom blueprint actions/routes.
For example:
module.exports['swagger-generator'] = {
updateBlueprintActionTemplates: function(blueprintActionTemplates) {
blueprintActionTemplates.search = { ... };
return blueprintActionTemplates;
}
}The blueprintActionTemplates object contains keys of the blueprint action names
and values as per the following example (refer to the
source code for the default templates):
let blueprintActionTemplates = {
findone: {
summary: 'Get {globalId} (find one)',
description: 'Look up the **{globalId}** record with the specified ID.',
externalDocs: {
url: 'https://sailsjs.com/documentation/reference/blueprint-api/find-one',
description: 'See https://sailsjs.com/documentation/reference/blueprint-api/find-one'
},
parameters: [
'primaryKeyPathParameter', // special case; filtered and substituted during generation phase
{ $ref: '#/components/parameters/LimitQueryParam' },
],
resultDescription: 'Responds with a single **{globalId}** record as a JSON dictionary',
notFoundDescription: 'Response denoting **{globalId}** record with specified ID **NOT** found',
// if functions, each called with (blueprintActionTemplate, routeInfo, pathEntry)
modifiers: ['addSelectQueryParam', exampleModifierFunctionRef],
},
...
};Note that:
1. For summary and description strings the value {globalId} is replaced with the applicable Sails model value.
1. Parameters values are Swagger definitions, with the exception of the special string value
primaryKeyPathParameter, which may be used to include a reference to a model's primary key.
1. Modifiers are used to apply custom changes to the generated Swagger, noting that:
- String values are predefined in
generatePaths()(refer to the source code); valid modifiers are:addPopulateQueryParamaddSelectQueryParamaddOmitQueryParamaddModelBodyParamaddModelBodyParamUpdateaddResultOfArrayOfModelsaddAssociationPathParamaddAssociationFKPathParamaddAssociationResultOfArrayaddResultOfModeladdResultNotFoundaddResultValidationErroraddFksBodyParamaddShortCutBlueprintRouteNote
- Functions are called as
func(blueprintActionTemplate, routeInfo, pathEntry, tags, components)whereblueprintActionTemplatethe blueprint action template (see above) to which the modifier relatesrouteInfothe route information object (see above) for which the Swagger is being generatedpathEntrythe generated Swagger path entry to be modifiedtagsthe generated Swagger tag definitions to be modified/extendedcomponentsthe generated Swagger component definitions to be modified/extended
Post-processing Generated Swagger Output
The final generated Swagger output may be post-processed before it is written to
the output file using a post-processing function specified as the postProcess config option.
For situations where saving the generated swagger documentation JSON to a file is
not desired/appropriate, the postProcess config option may be used to specify
an alternate save mechanism.
Note that if swaggerJsonPath config option is empty/null/undefined the output file will not be written.
For example:
module.exports['swagger-generator'] = {
postProcess: function(specifications) {
let sch = specifications.components.schemas;
Object.keys(sch).map(k => {
sch[k].description = sck[k].description.toUpperCase();
});
}
}Testing
Clone this repository
Install all development dependencies
npm install- Then run test
npm testContribute
Fork this repo and push in your ideas. Do not forget to add a bit of test(s) of what value you adding.
- stick to conventional commit message here or read more angular commit pattern
- While developing, you can run the below command to start nodemon watch too run linting and testing on
.tschanges
npm run devChangelog
See the different releases here
License
MIT License (MIT)
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
6 years ago
6 years ago
6 years ago
6 years ago
7 years ago
7 years ago
7 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago