{"id":16596526,"url":"https://github.com/mikestead/swagger-routes","last_synced_at":"2025-10-25T21:03:06.747Z","repository":{"id":3568902,"uuid":"48966775","full_name":"mikestead/swagger-routes","owner":"mikestead","description":"Generate Express or Restify route handlers from a Swagger specification","archived":false,"fork":false,"pushed_at":"2022-12-06T21:02:52.000Z","size":242,"stargazers_count":20,"open_issues_count":20,"forks_count":9,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-02-27T14:30:41.033Z","etag":null,"topics":["express","openapi","rest","restify","route-handlers","swagger"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mikestead.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-01-04T00:56:03.000Z","updated_at":"2021-04-16T02:20:58.000Z","dependencies_parsed_at":"2023-01-13T12:37:21.240Z","dependency_job_id":null,"html_url":"https://github.com/mikestead/swagger-routes","commit_stats":null,"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikestead%2Fswagger-routes","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikestead%2Fswagger-routes/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikestead%2Fswagger-routes/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mikestead%2Fswagger-routes/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mikestead","download_url":"https://codeload.github.com/mikestead/swagger-routes/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243830932,"owners_count":20354851,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["express","openapi","rest","restify","route-handlers","swagger"],"created_at":"2024-10-11T23:53:31.735Z","updated_at":"2025-10-25T21:03:01.726Z","avatar_url":"https://github.com/mikestead.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Swagger Routes\n\n[![Build Status](https://travis-ci.org/mikestead/swagger-routes.svg?branch=master)](https://travis-ci.org/mikestead/swagger-routes) [![npm version](https://img.shields.io/npm/v/swagger-routes.svg?style=flat-square)](https://www.npmjs.com/package/swagger-routes)\n\nA tool to generate and register [Restify](http://restify.com) or [Express](http://expressjs.com) route handlers from a \n[Swagger 2.0](http://swagger.io) ([OpenAPI](https://openapis.org)) specification.\n\n### Usage\n\nRequires Node v4.0+\n\n#### Express\n\n```javascript\nconst swaggerRoutes = require('swagger-routes')\nconst express = require('express')\nconst app = express()\n\nswaggerRoutes(app, {\n    api: './api.yml',\n    handlers:  './src/handlers',\n    authorizers: './src/handlers/security'\n})\napp.listen(8080)\n```\n\n#### Restify\n\n```javascript\nconst swaggerRoutes = require('swagger-routes')\nconst restify = require('restify')\nconst server = restify.createServer()\n\nswaggerRoutes(server, {\n    api: './api.yml',\n    handlers:  './src/handlers',\n    authorizers: './src/handlers/security'\n})\nserver.listen(8080)\n```\n\n##### Options\n\n- `api`: path to your Swagger spec, or the loaded spec reference.\n- `docsPath`: url path to serve your swagger api json. Defaults to `/api-docs`.\n- `docsMiddleware`: An optional middleware function that can be used to secure the api docs endpoint.\n- `handlers`: directory where your handler files reside. Defaults to `./handlers`. Can alternatively be a function to return a handler function given an operation.\n- `authorizers`: directory where your authorizer files reside. Defaults to `./security`. Can alternatively be a function to return an authorizer middleware given a swagger security scheme.\n- `maintainHeaders`: Keeps your generated handler doc headers in sync with your Swagger api. Default is false.\n\n### Operation Handlers\n\nYou have the option to define and maintain a handler file for each Swagger operation, or alternatively\nprovide a factory function which creates a handler function given an operation.\n\n#### Handler Files\n\nUsing individual handler files is a good choice if each handler needs unique logic to deal with an operation request.\n\nA handler file must be named after the Swagger operation it handles e.g. `listPets.js`.\n\nAll handler files must reside in the same directory, unless the `group` option is enabled, \nin which case the handler file should sit under a folder of its primary tag name (see Generating Handler Files below).\n\n##### File Contents\n\nA function called `handler` should be exported to deal with an incoming operation request.\n\n```javascript\nexports.handler = function listPets(req, res, next) {\n\n}\n```\nYou also have the option to export a `middleware` function to be executed before the handler.\n\n```javascript\nexports.middleware = preprocess\n\nfunction preprocess(req, res, next) {\n    next()\n}\n```\nMiddleware can be an ordered list.\n\n```javascript\nexports.middleware = [\n    function preprocess1(req, res, next) { next() },\n    function preprocess2(req, res, next) { next() }\n]\n```\n\n##### Generating Handler Files\n\nTo save you some time there's a bundled tool to generate handler files based on operations in\nyour Swagger spec, together with a [Mustache](https://mustache.github.io) template.\n\nThis tool is on by default so check your handlers folder the first time you run `swaggerRoutes` and\nit should be poulated with handler stubs for each operation defined in your Swagger document.\n\nEach time you start your app `swaggerRoutes` will see if you have any missing operation handlers and generate\nstub handler for any which are. If a handler file exists it won't be touched, i.e. this is non-destructive so you are free\nto edit them.\n\nNote that if you turn on the `syncHeaders` option then the header of your handler files _will_ be \nupdated each run based on your Swagger api. This keeps your handler documentation up to date so \nyou can easily see what parameters accompany a request for a given operation. It will overwrite\nany edits you make to the header so only turn on if you don't plan on manually editing them.\n\nWhen a re-run finds handlers no longer in use they will be renamed with an `_` prefix, so\n`listPets.js` would become `_listPets.js`. This allows you to identify handlers no longer in use\nand remove / rename them if you wish.\n\nIf you later enable a handler again in your spec and re-run, then the underscore will be removed.\n\nNote that this feature of prefixing removed handlers is only currently supported when the `group`\noptions is not enabled.\n\nThe default template is defined [here](https://github.com/mikestead/swagger-routes/blob/master/template/handler.mustache) but you can supply your own by expanding the `handlers` option e.g.\n\n```javascript\n{\n    ...\n    handlers: {\n        path: './src/handlers',\n        template: './template/handler.mustache', // can also be set with a loaded template\n        getTemplateView: operation =\u003e operation, // define the object to be rendered by your template\n        create: operation =\u003e (req, res) =\u003e {}, // see Handler Factory section for details\n        generate: true, // hander file generation on by default\n        group: false // when true each handler file will be placed under a directory named after its primary tag\n    }\n}\n```\n\n#### Handler Factory\n\nThe factory function is a better option to a file if handlers are quite similar e.g. delegate their request\nprocessing onto service classes.\n\n##### Creating a Handler Factory\n\nYou can define `handlers` as a function when registering your routes. It receives a Swagger [operation](#operation-object) and returns the request handler responsible for dealing with it.\n\n```javascript\nconst swaggerRoutes = require('swagger-routes')\n\nswaggerRoutes(app, {\n    api: './api.yml',\n    handlers:  createHandler\n})\n\nfunction createHandler(operation) {\n    return function handler(req, res, next) {\n        res.send(operation.id)\n    }\n}\n```\n\nIf a handler function is returned then it will take precedence over a handler file for the same operation.\n\n##### Route Middleware\n\nJust as a file handler can define route middleware, so can `createHandler`.\n\n```javascript\nfunction createHandler(operation) {\n    return {\n        middleware: function preprocess(req, res, next) { next() },\n        handler: function handler(req, res, next) { res.send(operation.id) }\n    }\n}\n```\n\nAs before, route middleware can be an ordered list.\n\n```javascript\nfunction createHandler(operation) {\n    return {\n        middleware: [\n            function preprocess1(req, res, next) { next() },\n            function preprocess2(req, res, next) { next() }\n        ],\n        handler: function handler(req, res, next) { res.send(operation.id) }\n    }\n}\n```\n\n### Authorizers\n\nWhen your Swagger api specifies one or more \n[security schemes](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#implicit-oauth2-sample) \nthen routes which opt into one or more of these schemes can be protected by authorizer middleware.\n\nJust like handlers, you can define an authorizer in a file or via a factory.\n\n#### File Authorizer\n\nThe file should be named after the security scheme it protects e.g. `petstore_auth.js`, and reside in the directory path defined by the `authorizers` option. It should export a single middleware function to authorize a request.\n\n```javascript\nmodule.exports = function petstore_auth(req, res, next) {\n    const token = decodeToken(req.headers.authorization)\n    if (token) {\n        const scopes = getTokenScopes(token)\n        next(req.verifyScopes(scopes))\n    } else {\n        const error = new Error('Unauthorized')\n        error.status = error.statusCode = 401\n        next(error)\n    }\n}\n```\n\nThe above is one example of how this can work.\n\nAs you can see a `verifyScopes` function is supplied to the req if the security scheme is OAuth2.\nIt takes an array of scopes you decode from the authenticated request and verifies that the \nrequired scope(s) defined be the scheme are present. If they're not a `403 Forbidden` \n[error](https://en.wikipedia.org/wiki/HTTP_403#Difference_from_status_.22401_Unauthorized.22) is returned.\n\nWhen multiple oauth scopes are defined for the security of an endpoint, Swagger expects all of them to be \npresent for a call to proceed. As an extension to this, `swagger-routes` also supports the logical OR of \ntoken scopes, so if *any* exist then `verifyScopes` succeeds.\n\nAs an example, this definition below will pass the auth check if either a `Catalog` OR `Playback` scope exist.\n\n```yaml\n  ...\n  security:\n    - accountAuth:\n      - Catalog\n      - Playback\n  x-security:\n    accountAuth:\n      OR_scopes: true\n```\n\nRemember if no credentials are supplied a `401 Unauthorized` should be returned.\n\n##### Generating Authorizer Files\n\nMuch like handler files, authorizer file stubs will be generated and managed for you too.\n\nThe default template is defined [here](https://github.com/mikestead/swagger-routes/blob/master/template/authorizer.mustache) \nbut you can supply your own by expanding the `authorizers` option e.g.\n\n```javascript\n{\n    ...\n    authorizers: {\n    \tpath: './src/handlers/security',\n    \ttemplate: './template/authorizer.mustache', // can also be set with a loaded template\n    \tgetTemplateView: operation =\u003e operation, // define the object to be rendered by your template\n    \tcreate: operation =\u003e (req, res) =\u003e {}, // see Authorizer Factory section for details\n    \tgenerate: true // authorizer file generation on by default\n    }\n}\n```\n\n#### Authorizer Factory\n\n```javascript\nconst swaggerRoutes = require('swagger-routes')\n\nswaggerRoutes(app, {\n    api: './api.yml',\n    authorizers: createAuthorizer\n})\n\nfunction createAuthorizer(schemeId, securityScheme) {\n    return function authorizer(req, res, next) {\n        const token = decodeToken(req.headers.authorization)\n        if (token) {\n            const scopes = getTokenScopes(token)\n            next(req.verifyScopes(scopes))\n        } else {\n            const error = new Error('Invalid access token')\n            error.status = error.statusCode = 401\n            next(error)\n        }\n    }\n}\n```\n\n### Request Validation\n\nEach incoming request which makes it to a handler will be run through request validation middleware. \nThis executes [JSON Schema](http://json-schema.org) validation on the request to ensure it meets \nthe Swagger specification you've defined. A failure to meet this requirement will cause the request \nto fail and the handler not to be executed.\n\n### Swagger Host\n\nStatically setting the `host` property of your Swagger api can be error prone if you run the api \nin different environments (QA, Staging, Production), that's why I'd recommended removing its\ndefinition from your specification. This will by default then \n[resolve to the host](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#swagger-object), including port, the spec \nis served from.\n\nIf this still isn't sufficient you have a couple of other options.\n \n1. Set `API_HOST` environment variable for your node instance. SwaggerRoutes will pick this up and use it.\n1. Set the `app.swagger.host` manually from within your app after you've called `swaggerRoutes`.\n\n```javascript\nconst server = app.listen(3000, '0.0.0.0', () =\u003e {\n    app.swagger.host = `${server.address().address}:${server.address().port}`\n})\n```\n\n## Route Stack Execution Order\n\n1. `authorizer middleware` If there are security restrictions on a route then an authorizer for each will need to verify the rights attached to the request.\n1. `custom middleware` If the route defines one or more middleware these will be executed in order.\n1. `validation middleware` The incoming request will now be validated against the Swagger spec for the given operation.\n1. `handler` Assuming all previous steps pass, the handler is now executed.\n\n## Advanced Usage\n\n### Registering Multiple Swagger Apis\n\nYou may be in the situation where you have a Swagger definition for each major version of your api.\nIf this is the case, and you want to handle each on the same server, then you are free to register\nmore than one spec.\n\n```javascript\nswaggerRoutes(server, {\n    api: './api-v1.yml',\n    handlers:  './src/handlers/v1',\n    authorizers: './src/handlers/v1/security'\n})\n\nswaggerRoutes(server, {\n    api: './api-v2.yml',\n    handlers:  './src/handlers/v2',\n    authorizers: './src/handlers/v2/security'\n})\n```\nYou'll need to ensure that there's no conflict in route paths between each. The best\nway to do that would be to add a unique `basePath` to each spec, say `/v1`, `/v2` etc.\n\n## Operation Object\n\nAn operation object inherits its properties from those defined in the [Swagger spec](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#operationObject).\n\nThere are only a few differences / additions.\n\n- `id`: Replaces `operationId`.\n- `path`: The route path of this operation.\n- `method`: The http method\n- `consumes`: Populated with the top level `consumes` unless the operation defines its own.\n- `produces`: Populated with the top level `produces` unless the operation defines its own.\n- `paramGroupSchemas`: JSON Schema for each param group ('header', 'path', 'query', 'body', 'formData') relevant to the operation.\n\n## Acknowledgments\n\nInspiration for this library came primarily from time spent using [swaggerize-express](https://github.com/krakenjs/swaggerize-express).\nIt's a great library which you should check out.\n\nMy reasoning behind writing a new, alternate implementation was the wish to base all\nrouting off operation ids and not paths. This aligns with how Swagger client code gen\nworks, making it easier to see your client SDKs and server code base as a whole.\n\nI also wanted to automate away much of the boilerplate code being written and support\nRestify and Express in a single library, given their similarities.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmikestead%2Fswagger-routes","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmikestead%2Fswagger-routes","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmikestead%2Fswagger-routes/lists"}