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.
$ npm install sails-hook-swagger-generator --save
Copy the content of generatedSwagger and paste it in Swagger Online Editor.
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.
By default, the Swagger Generator Sails Hook generates:
config/routes.js
; andconfig/routes.js
(full details cannot be inferred
for custom routes without additional information being provided - see below).globalId
's.See #28
Documentation detail and customisation of most aspects of the generated Swagger can be achieved by adding:
config/swaggergenerator.js
. This provides direct JSON
used as the template for the output Swagger/OpenAPI.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).@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.
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: 'https://theoomoregbee.github.io/'}
},
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:
disabled
attribute is used to disable the module (e.g you may want to disable it on production).swaggerJsonPath
where to generate the swagger.json
file to; defaults to sails.config.appPath + '/swagger/swagger.json'
and output file will not be written if empty/null/undefined (see postProcess
below for alternate save mechanism).swagger
object 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.defaults
object should contain the responses
element; defaults to the above if not specified.excludeDeprecatedPutBlueprintRoutes
should
deprecated PUT
blueprint
routes be excluded from generated Swagger output; defaults to true
.includeRoute
function used to filter routes to be included in generated Swagger output; see advanced section below.updateBlueprintActionTemplates
allows customisation of the templates used to generate Swagger for blueprints; see advanced section below.postProcess
allows 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.Documentation detail and customisation of most aspects of the generated Swagger for custom routes may be achieved by:
swagger
(must be of type SwaggerActionAttribute for actions, based on OpenApi.Operation) to individual route configurations in config/routes.js
.swagger
(must be of type SwaggerControllerAttribute) to the exports of a controller file, standalone action file or actions2 file.swagger
(must be of type SwaggerModelAttribute) to the exports of a model file.@swagger
comments to Sails
model files,
controller files,
standalone action files or
actions2 files; specifically:
@swagger
documentation under the /{actionName}
path for the route (controllers/actions), or@swagger
documentation under the /{blueprintAction}
path for the route (models), or@swagger
documentation under tags
and components
paths for adding to the top-level Swagger/OpenAPI definitions.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' }
}
}
}
}
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:
swagger
added to a controller file action function.swagger
to the exports of a controller file, standalone
action file or actions2 file:
swagger.actions.{actionName}
name. See UserController.js;swagger.actions.{actionFileName|actions2FileName}
object. See
actions2.js
Note: actionFileName|actions2FileName
must correspond to the filename;swagger.actions.allActions
e.g. use this to apply common tags to all actions for a controller.tags
and components
elements for adding to the
top-level Swagger/OpenAPI definitions. See example in either
UserController.js
or actions2.js.@swagger
comments to controller file, standalone action file or actions2 file:
@swagger
documentation under the /{actionName}
path for the controller file actions,@swagger
documentation under the /{actionFileName|actions2FileName}
path for standalone action or actions2 files,@swagger
documentation under the /allActions
path to be applied to all actions for the controller, or@swagger
documentation under tags
and components
paths for adding to the top-level Swagger/OpenAPI definitions.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.
swagger
object
in actions2 file.meta.swagger
to document the attributes
Swagger/OpenAPI schema associated with the input value. See example in
actions2.js.meta.swagger.exclude
to true
.meta.swagger.in
. The values query
/header
/path
/cookie
may be used to produce Swagger operation
parameters and the value body
may be used to produce requestBody
schema 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
};
Documentation detail and customisation of most aspects of the generated Swagger for blueprint routes may be achieved by:
swagger
to individual models e.g. api/models/modelName.js
:
swagger.modelSchema
e.g. use this to apply detailed documentation via the description
field;swagger.modelSchema
may be used to specify
tag names (as a string[]
) 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;swagger.actions.{blueprintAction}
name;swagger.actions.allActions
e.g. use this to apply common externalDocs
to all blueprint actions for the model; orswagger.tags
and swagger.components
elements for adding to the top-level Swagger/OpenAPI definitions.description
, moreInfoUrl
and example
).
Note that applicable Sails attributes,
automigrations and
validations are also parsed.meta.swagger
to individual model attributes to document
the attributes Swagger/OpenAPI schema. See example in Pet.js.@swagger
comments to model files:
@swagger
documentation under the /{globalId}
to add documentation to
the model's Swagger schema (or tags as noted above),@swagger
documentation under the /{blueprintAction}
to add per-action
documentation for the
model blueprint actions,@swagger
documentation under the /allActions
path to be applied to all
blueprint actions for the model, or@swagger
documentation under tags
and components
paths for adding to the
top-level Swagger/OpenAPI definitions.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:
{ $ref: '#/components/schemas/modelName' }
.{ $ref: '#/components/parameters/ModelPKParam-modelName' }
.These may be re-used (referenced) if/as applicable within custom route documentation.
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 are added to the top-level Swagger/OpenAPI definitions as follows:
description
and externalDocs
elements.Note that a final clean-up phase is run after processing, which performs the following:
Elements of components are added to the top-level Swagger/OpenAPI definitions as follows:
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: {},
};
Three mechanisms are provided to enable advancing filtering of the Swagger generation process:
includeRoute()
function used to filter routes to be included in generated Swagger output.updateBlueprintActionTemplates()
function allows customisation of the templates used to generate Swagger for blueprints.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
.
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.
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;
}
}
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:
{globalId}
is replaced with the applicable Sails model value.primaryKeyPathParameter
, which may be used to include a reference to a model's primary key.generatePaths()
(refer to the source code);
valid modifiers are:
addPopulateQueryParam
addSelectQueryParam
addOmitQueryParam
addModelBodyParam
addModelBodyParamUpdate
addResultOfArrayOfModels
addAssociationPathParam
addAssociationFKPathParam
addAssociationResultOfArray
addResultOfModel
addResultNotFound
addResultValidationError
addFksBodyParam
addShortCutBlueprintRouteNote
func(blueprintActionTemplate, routeInfo, pathEntry, tags, components)
where
blueprintActionTemplate
the blueprint action template (see above) to which the modifier relatesrouteInfo
the route information object (see above) for which the Swagger is being generatedpathEntry
the generated Swagger path entry to be modifiedtags
the generated Swagger tag definitions to be modified/extendedcomponents
the generated Swagger component definitions to be modified/extendedThe 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();
});
}
}
Clone this repository
Install all development dependencies
npm install
npm test
Fork this repo and push in your ideas. Do not forget to add a bit of test(s) of what value you adding.
.ts
changesnpm run dev
See the different releases here
MIT License (MIT)