{"id":22221111,"url":"https://github.com/davesag/swagger-routes-express","last_synced_at":"2025-04-06T13:12:06.355Z","repository":{"id":32838982,"uuid":"144020410","full_name":"davesag/swagger-routes-express","owner":"davesag","description":"Connect your Express route controllers to restful paths using your Swagger definition file","archived":false,"fork":false,"pushed_at":"2024-04-23T05:45:07.000Z","size":2651,"stargazers_count":86,"open_issues_count":3,"forks_count":20,"subscribers_count":5,"default_branch":"develop","last_synced_at":"2024-05-02T00:12:40.939Z","etag":null,"topics":["api-server","expressjs","middleware","nodejs","openapi","swagger","swagger2"],"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/davesag.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["davesag"]}},"created_at":"2018-08-08T13:50:12.000Z","updated_at":"2024-05-29T06:19:19.214Z","dependencies_parsed_at":"2023-12-15T03:25:57.565Z","dependency_job_id":"155d2ff7-a123-4ab5-9f03-3f018232141f","html_url":"https://github.com/davesag/swagger-routes-express","commit_stats":null,"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davesag%2Fswagger-routes-express","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davesag%2Fswagger-routes-express/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davesag%2Fswagger-routes-express/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davesag%2Fswagger-routes-express/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/davesag","download_url":"https://codeload.github.com/davesag/swagger-routes-express/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247485290,"owners_count":20946398,"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":["api-server","expressjs","middleware","nodejs","openapi","swagger","swagger2"],"created_at":"2024-12-02T23:12:18.624Z","updated_at":"2025-04-06T13:12:06.331Z","avatar_url":"https://github.com/davesag.png","language":"JavaScript","funding_links":["https://github.com/sponsors/davesag"],"categories":[],"sub_categories":[],"readme":"# swagger-routes-express\n\nConnect [`Express`](http://www.expressjs.com) route controllers to restful paths using a [`Swagger`](http://swagger.io) v2 or [`OpenAPI`](https://www.openapis.org) v3 definition file.\n\n[![CircleCI](https://dl.circleci.com/status-badge/img/gh/davesag/swagger-routes-express/tree/develop.svg?style=svg)](https://dl.circleci.com/status-badge/redirect/gh/davesag/swagger-routes-express/tree/develop)\n\n## Assumptions\n\nThis library assumes you are using:\n\n1. [NodeJS](https://nodejs.org) _version 6.4.0_ or better,\n2. [`expressjs`](http://www.expressjs.com) _any version_, and\n3. [`swagger`](http://swagger.io) _version 2_, or [`OpenAPI`](https://www.openapis.org) _version 3_.\n\n## Install\n\nAdd `swagger-routes-express` as a `dependency`:\n\n```sh\nnpm i swagger-routes-express\n```\n\n## Examples\n\n### A simple API\n\nAssume the following API route controllers, defined in `./api/index.js` as follows:\n\n```js\nconst { name, version, description } = require('../../package.json')\n\nconst versions = (req, res) =\u003e {\n  res.json([\n    {\n      version: 1,\n      path: '/api/v1'\n    }\n  ])\n}\n\nconst ping = (req, res) =\u003e {\n  res.json({\n    name,\n    description,\n    version,\n    uptime: process.uptime()\n  })\n}\n\nmodule.exports = { ping, versions }\n```\n\n### Swagger Version 2 example\n\nGiven a Swagger (v2) YAML file `api.yml` along the lines of:\n\n```yml\nswagger: '2.0'\ninfo:\n  description: Something about the API\n  version: '1.0.0'\n  title: 'Test API'\nbasePath: '/api/v1'\nschemes:\n  - 'https'\n  - 'http'\npaths:\n  /:\n    get:\n      tags:\n        - 'root'\n      summary: 'Get API Version Information'\n      description: 'Returns a list of the available API versions'\n      operationId: 'versions'\n      produces:\n        - 'application/json'\n      responses:\n        200:\n          description: 'success'\n          schema:\n            $ref: '#/definitions/ArrayOfVersions'\n  /ping:\n    get:\n      tags:\n        - 'root'\n      summary: 'Get Server Information'\n      description: 'Returns information about the server'\n      operationId: 'ping'\n      produces:\n        - 'application/json'\n      responses:\n        200:\n          description: 'success'\n          schema:\n            $ref: '#/definitions/ServerInfo'\ndefinitions:\n  # see https://swagger.io/docs/specification/data-models/data-types\n  APIVersion:\n    type: 'object'\n    properties:\n      version:\n        type: 'integer'\n        format: 'int64'\n      path:\n        type: 'string'\n  ServerInfo:\n    type: 'object'\n    properties:\n      name:\n        type: 'string'\n      description:\n        type: 'string'\n      version:\n        type: 'string'\n      uptime:\n        type: 'number'\n  ArrayOfVersions:\n    type: 'array'\n    items:\n      $ref: '#/definitions/APIVersion'\n```\n\n### OpenAPI Version 3 example\n\n```yml\nopenapi: 3.0.0\ninfo:\n  description: Something about the API\n  version: 1.0.0\n  title: Test API\npaths:\n  /:\n    get:\n      tags:\n        - root\n      summary: Get API Version Information\n      description: Returns a list of the available API versions\n      operationId: versions\n      responses:\n        '200':\n          description: success\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/ArrayOfVersions'\n  /ping:\n    get:\n      tags:\n        - root\n      summary: Get Server Information\n      description: Returns information about the server\n      operationId: ping\n      responses:\n        '200':\n          description: success\n          content:\n            application/json:\n              schema:\n                $ref: '#/components/schemas/ServerInfo'\nservers:\n  - url: /api/v1\ncomponents:\n  schemas:\n    APIVersion:\n      type: object\n      properties:\n        version:\n          type: integer\n          format: int64\n        path:\n          type: string\n    ServerInfo:\n      type: object\n      properties:\n        name:\n          type: string\n        description:\n          type: string\n        version:\n          type: string\n        uptime:\n          type: number\n    ArrayOfVersions:\n      type: array\n      items:\n        $ref: '#/components/schemas/APIVersion'\n```\n\n## Connecting your Express server\n\nYou can `connect` your `Express` app or router as follows:\n\n```js\nconst express = require('express')\nconst YAML = require('yamljs')\nconst { connector } = require('swagger-routes-express')\nconst api = require('./api')\n\nconst makeApp = () =\u003e {\n  const apiDefinition = YAML.load('api.yml') // load the api as json\n  const connect = connector(api, apiDefinition) // make the connector\n  const app = express() // make the app\n\n  // do any other app stuff, such as wire in passport, use cors etc\n\n  connect(app) // attach the routes\n\n  // add any error handlers last\n\n  return app\n}\n```\n\nWith the result that requests to `GET /` will invoke the `versions` controller and a request to `/ping` will invoke the `ping` controller.\n\n## Options\n\nYou can pass in an optional `options` object as a third parameter to the `connector` function.\n\n```js\nconst connect = connector(api, apiDefinition, options)\n```\n\nIf you don't pass in any options the defaults are:\n\n```js\n{\n  security: {},\n  middleware: {},\n  onCreateRoute: undefined,\n  apiSeparator: '_',\n  notFound: : require('./routes/notFound'),\n  notImplemented: require('./routes/notImplemented'),\n  rootTag: 'root', // only used in Swagger V2 docs\n  variables: {}, // only used in OpenAPI v3 docs\n  INVALID_VERSION: require('./errors').INVALID_VERSION\n}\n```\n\n### Adding security middleware handlers\n\nThere are several ways to add middleware handlers, and they can be combined to provide a high degree of customisation and flexibility.\n\n#### Specify Auth middleware by name in the API definition yml file\n\nIf your swagger document defines security, you can map this to your own Auth Middleware by passing in a `security` option to the `connector`.\n\n##### Security with scopes\n\nFor example if your path defines oAuth style `security` like:\n\n```yml\npaths:\n  /private\n    get:\n      summary: some private route\n      security:\n        - access: ['read', 'write']\n  /admin\n    get:\n      summary: some admin route\n      security:\n        - access: ['admin']\n```\n\nSupply a `security` option as follows\n\n```js\nconst options = {\n  security: {\n    'read,write': readWriteAuthMiddlewareFunction,\n    admin: adminAuthMiddlewareFunction\n  }\n}\n```\n\n##### Security without scopes\n\nIf your path defines `security`, and its `scopes` array is empty, you use its name in the `security` option.\n\nGiven:\n\n```yml\npaths:\n  /private\n    get:\n      summary: some private route\n      security:\n        - apiKey: []\n```\n\nSupply a `security` option like:\n\n```js\nconst options = {\n  security: {\n    apiKey: myAuthMiddlewareFunction\n  }\n}\n```\n\n#### Return an array of controllers\n\nYour API might wish to leverage some middleware functions but you don't want to have to specify them all in the API document itself.\n\nYour API controller functions themselves can return arrays of controller functions.\n\n##### Example\n\nIn this case `/api/v1/createThings/index.js` returns an array of controller functions with bespoke middleware controllers running in sequence, and then runs the controller in `/api/v1/createThings/createThings.js`\n\n`/api/v1/createThings/index.js`\n\n```js\nconst { checkIfAllowed, stripPII } = require('middleware')\nconst actuallyCreateThings = require('./createThings')\n\nconst createThings = [checkIfAllowed, stripPII, actuallyCreateThings]\n```\n\nThe array of middleware and your controller will be executed in order, so it's important to put your actual controller logic last.\n\n#### Global security definitions\n\nBoth Swagger V2 and OpenAPI V3 allow you to define global `security`. The global `security` definition will be applied if there is no path-specific one defined.\n\n##### Exempting a path from global security\n\nIf you've defined global `security` but wish to exempt a specific path, then you can configure the path like:\n\n```yml\npaths:\n  /my-route\n    get:\n      summary: some route that is exempt from the default security\n      security: []\n```\n\n#### Further reading on Swagger and security\n\n- [Swagger V2 Authentication](https://swagger.io/docs/specification/2-0/authentication/), and\n- [Open API V3 Authentication](https://swagger.io/docs/specification/authentication/) docs.\n\n#### Notes\n\n- Only the **first** security option is used, the others are ignored. Your Auth Middleware function must handle any alternative authentication schemes. This can be achieved by returning an array of middleware controllers that culminates in the specific api controller you want.\n- Security middleware, wither defined at the global or path level, is applied first, then any controller specific arrays of middleware are applied,\n- Scopes, if supplied, are sorted alphabetically.\n\n#### What's an Auth Middleware function?\n\nAn Auth Middleware Function is simply an [Express Middleware function](https://expressjs.com/en/guide/using-middleware.html) that checks to see if the user making the request is allowed to do so.\n\nHow this actually works in your server's case is going to be completely application specific, but the general idea is your app needs to be able to log users in, or accept a token from a header, or somehow otherwise stick a user id, or some roles, into `req.user` or `req.session.user` or something like that. There are dozens of ways to do this. I recommend using something like [Passport](http://www.passportjs.org/packages/) to handle the specifics.\n\nYour Auth Middleware then just needs to check that the user / roles you've stored corresponds with what you'd like to allow that user to do.\n\n```js\nasync function correspondingMiddlewareFunction(req, res, next) {\n  // previously you have added a userId to req (say from an 'Authorization: Bearer token' header)\n  // how you check that the token is valid is up to your app's logic\n  if (await isValidToken(req.user.token)) return next()\n\n  // otherwise reject with an error\n  return res.status(401).json({ error: \"I'm afraid you can't do that\" })\n}\n```\n\n- [More information…](https://duckduckgo.com/?q=express+auth+middleware) (via DuckDuckGo)\n\n### Adding other path-level middleware\n\nYou can add your own path specific middleware by passing in a `middleware` option:\n\n```js\n{\n  middleware: {\n    myMiddleware: someMiddlewareFunction\n  }\n}\n```\n\nWith either Swagger v2 or OpenAPI v3, add an `x-middleware` option in the path specification:\n\n```yml\npaths:\n  /special:\n    get:\n      summary: some special route\n      x-middleware:\n        - myMiddleware\n```\n\nThe `someMiddlewareFunction` will be inserted **after** any Auth Middleware.\n\n### Adding hooks\n\nYou can supply an `onCreateRoute` handler function with the options with signature\n\n```js\nconst onCreateRoute = (method, descriptor) =\u003e {\n  const [path, ...handlers] = descriptor\n  console.log('created route', method, path, handlers)\n}\n```\n\nThe method will be one of 'get', 'post', 'patch', 'put', or 'delete'.\n\nThe `descriptor` is an array of:\n\n```js\n;[\n  path, // a string. Swagger param formats will have been converted to express route formats.\n  security, // an auth middleware function (if needed)\n  ...middleware, // other middleware functions (if supplied)\n  controller //  then finally the route controller function\n]\n```\n\n### Mapping to nested API routes\n\nIf your `./api` folder contains nested controllers such as:\n\n```text\n/api/v1/createThing.js\n```\n\nIt's not uncommon for `./index.js` to expose this as `v1_createThing`, but in swagger the `operationId` might specify it as `v1/createThing`.\n\nYou can supply your own `apiSeparator` option in place of `_` to map from `/`.\n\n### Arrays of route controllers\n\nIn this case `/api/v1/createThings.js` returns an array of controller functions with bespoke middleware controllers running in sequence. This is a shortcut for otherwise specifying middleware as outlined above.\n\n### Missing Route Controllers\n\nIf a route controller is defined as an `operationId` in Swagger but there is no corresponding controller, a default `notImplemented` controller will be inserted that simply responds with a `501` error. You can also specify your own `notImplemented` controller in `options`.\n\nIf no `operationId` is supplied for a path then a default `notFound` controller that responds with a `404` status will be inserted. You can also specify your own `notFound` controller in `options`.\n\n### Base paths\n\n#### Swagger Version 2\n\nFor the root path `/` we check the route's `tags`. If the first `tag` defined for a path is `'root'` we don't inject the api `basePath`, otherwise we do. You can define your own `rootTag` option to override this behaviour.\n\n#### OpenAPI Version 3\n\nThe OpenAPI V3 format allows you to define both a default `servers` array, and `path` specific `servers` arrays. The `url` fields in those arrays are parsed, ignoring any absolute URLS (as they are deemed to refer to controllers external to this API Server).\n\nThe spec allows you to include template variables in the `servers`' `url` field. To accommodate this you can supply a `variables` option in `options`. Any variables you specify will be substituted.\n\n## Generating API summary information\n\nYou can generate a summary of your Swagger v2 or OpenAPI v3 API specification in the form:\n\n```js\n{\n  info: { name, version, description },\n  paths: { [method]: ['/array', '/of', '/normalised/:paths'] }\n}\n```\n\nas follows:\n\n```js\nconst YAML = require('yamljs')\nconst { summarise } = require('swagger-routes-express')\n\nconst apiDefinition = YAML.load('api.yml')\nconst apiSummary = summarise(apiDefinition)\n```\n\n## Upgrading from Swagger Routes Express V2 to V3\n\nThese docs refer to Version 3 of Swagger Routes Express which changed the way you invoke the `connector`.\n\n### The old way\n\n```js\nconst connector = require('swagger-routes-express')\n```\n\n### The new way\n\n```js\nconst { connector } = require('swagger-routes-express')\n```\n\n## Development\n\n### Branches\n\n\u003c!-- prettier-ignore --\u003e\n| Branch | Status | Coverage | Audit | Notes |\n| ------ | ------ | -------- | ----- | ----- |\n| `develop` | [![CircleCI](https://dl.circleci.com/status-badge/img/gh/davesag/swagger-routes-express/tree/develop.svg?style=svg)](https://dl.circleci.com/status-badge/redirect/gh/davesag/swagger-routes-express/tree/develop) | [![codecov](https://codecov.io/gh/davesag/swagger-routes-express/branch/develop/graph/badge.svg)](https://codecov.io/gh/davesag/swagger-routes-express) | [![Vulnerabilities](https://snyk.io/test/github/davesag/swagger-routes-express/develop/badge.svg)](https://snyk.io/test/github/davesag/swagger-routes-express/develop) | Work in progress |\n| `main` | [![CircleCI](https://dl.circleci.com/status-badge/img/gh/davesag/swagger-routes-express/tree/main.svg?style=svg)](https://dl.circleci.com/status-badge/redirect/gh/davesag/swagger-routes-express/tree/main) | [![codecov](https://codecov.io/gh/davesag/swagger-routes-express/branch/main/graph/badge.svg)](https://codecov.io/gh/davesag/swagger-routes-express) | [![Vulnerabilities](https://snyk.io/test/github/davesag/swagger-routes-express/main/badge.svg)](https://snyk.io/test/github/davesag/swagger-routes-express/main) | Latest stable release |\n\n### Prerequisites\n\n- [NodeJS](htps://nodejs.org). I use [`nvm`](https://github.com/creationix/nvm) to manage Node versions — `brew install nvm`.\n\n### Test it\n\n- `npm test` — runs the unit tests.\n- `npm run test:unit:cov` - run the unit tests with coverage.\n\n### Lint it\n\n```sh\nnpm run lint\n```\n\n## Starter templates and examples of use\n\nThe following projects use `swagger-routes-express` as a starter template.\n\n- My own [`api-server-boilerplate`](https://github.com/davesag/api-server-boilerplate), and\n- [`node-express-open-api-skeleton`](https://github.com/ReubenFrimpong/node-express-open-api-skeleton) by [Reuben Frimpong](https://github.com/ReubenFrimpong).\n\n_Note_: If you have a template or example of use to add to this list please just raise a PR and I'll take a look.\n\n## Contributing\n\nPlease see the [contributing notes](CONTRIBUTING.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavesag%2Fswagger-routes-express","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdavesag%2Fswagger-routes-express","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavesag%2Fswagger-routes-express/lists"}