Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

fastify-swagger

Package Overview
Dependencies
Maintainers
6
Versions
100
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fastify-swagger - npm Package Compare versions

Comparing version 0.5.0 to 0.6.0

dynamic.js

293

index.js
'use strict'
const fp = require('fastify-plugin')
const fs = require('fs')
const path = require('path')
const yaml = require('js-yaml')
const setup = { dynamic: require('./dynamic'), static: require('./static') }
function fastifySwagger (fastify, opts, next) {
fastify.decorate('swagger', swagger)
const routes = []
fastify.addHook('onRoute', (routeOptions) => {
routes.push(routeOptions)
})
opts = opts || {}
opts.swagger = opts.swagger || {}
const info = opts.swagger.info || null
const host = opts.swagger.host || null
const schemes = opts.swagger.schemes || null
const consumes = opts.swagger.consumes || null
const produces = opts.swagger.produces || null
const basePath = opts.swagger.basePath || null
const securityDefinitions = opts.swagger.securityDefinitions || null
// by default the mode is dynamic, as plugin initially was developed
opts.mode = opts.mode || 'dynamic'
if (opts.exposeRoute === true) {
fastify.register(require('./routes'))
switch (opts.mode) {
case 'static':
setup.static(fastify, opts, next)
break
case 'dynamic':
setup.dynamic(fastify, opts, next)
break
default:
return next(new Error("unsupported mode, should be one of ['static', 'dynamic']"))
}
const cache = {
swaggerObject: null,
swaggerString: null
}
function swagger (opts) {
if (opts && opts.yaml) {
if (cache.swaggerString) return cache.swaggerString
} else {
if (cache.swaggerObject) return cache.swaggerObject
}
const swaggerObject = {}
var pkg
try {
pkg = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json')))
} catch (err) {
return next(err)
}
// Base swagger info
// this info is displayed in the swagger file
// in the same order as here
swaggerObject.swagger = '2.0'
if (info) {
swaggerObject.info = info
} else {
swaggerObject.info = {
version: '1.0.0',
title: pkg.name || ''
}
}
if (host) swaggerObject.host = host
if (schemes) swaggerObject.schemes = schemes
if (basePath) swaggerObject.basePath = basePath
if (consumes) swaggerObject.consumes = consumes
if (produces) swaggerObject.produces = produces
if (securityDefinitions) {
swaggerObject.securityDefinitions = securityDefinitions
}
swaggerObject.paths = {}
for (var route of routes) {
const url = formatParamUrl(route.url)
const method = route.method.toLowerCase()
const schema = route.schema
const swaggerRoute = swaggerObject.paths[url] || {}
if (schema && schema.hide) {
continue
}
const swaggerMethod = swaggerRoute[method] = {}
const parameters = []
// All the data the user can give us, is via the schema object
if (schema) {
// the resulting schema will be in this order
if (schema.summary) {
swaggerMethod.summary = schema.summary
}
if (schema.description) {
swaggerMethod.description = schema.description
}
if (schema.tags) {
swaggerMethod.tags = schema.tags
}
if (schema.consumes) {
swaggerMethod.consumes = schema.consumes
}
if (schema.querystring) {
getQueryParams(parameters, schema.querystring)
}
if (schema.body) {
const consumesAllFormOnly =
consumesFormOnly(schema) || consumesFormOnly(swaggerObject)
consumesAllFormOnly
? getFormParams(parameters, schema.body)
: getBodyParams(parameters, schema.body)
}
if (schema.params) {
getPathParams(parameters, schema.params)
}
if (schema.headers) {
getHeaderParams(parameters, schema.headers)
}
if (parameters.length) {
swaggerMethod.parameters = parameters
}
if (schema.deprecated) {
swaggerMethod.deprecated = schema.deprecated
}
if (schema.security) {
swaggerMethod.security = schema.security
}
}
swaggerMethod.responses = genResponse(schema ? schema.response : null)
if (swaggerRoute) {
swaggerObject.paths[url] = swaggerRoute
}
}
if (opts && opts.yaml) {
const swaggerString = yaml.safeDump(swaggerObject, { skipInvalid: true })
cache.swaggerString = swaggerString
return swaggerString
}
cache.swaggerObject = swaggerObject
return swaggerObject
}
next()
}
function consumesFormOnly (schema) {
const consumes = schema.consumes
return (
consumes &&
consumes.length === 1 &&
(consumes[0] === 'application/x-www-form-urlencoded' ||
consumes[0] === 'multipart/form-data')
)
}
function getQueryParams (parameters, query) {
if (query.type && query.properties) {
// for the shorthand querystring declaration
return getQueryParams(parameters, query.properties)
}
Object.keys(query).forEach(prop => {
const obj = query[prop]
const param = obj
param.name = prop
param.in = 'query'
parameters.push(param)
})
}
function getBodyParams (parameters, body) {
const param = {}
param.name = 'body'
param.in = 'body'
param.schema = body
parameters.push(param)
}
function getFormParams (parameters, body) {
const formParamsSchema = body.properties
if (formParamsSchema) {
Object.keys(formParamsSchema).forEach(name => {
const param = formParamsSchema[name]
delete param.$id
param.in = 'formData'
param.name = name
parameters.push(param)
})
}
}
function getPathParams (parameters, params) {
if (params.type && params.properties) {
// for the shorthand querystring declaration
return getPathParams(parameters, params.properties)
}
Object.keys(params).forEach(p => {
const param = {}
param.name = p
param.in = 'path'
param.required = true
param.description = params[p].description
param.type = params[p].type
parameters.push(param)
})
}
function getHeaderParams (parameters, headers) {
if (headers.type && headers.properties) {
// for the shorthand querystring declaration
const headerProperties = Object.keys(headers.properties).reduce((acc, h) => {
const required = (headers.required && headers.required.indexOf(h) >= 0) || false
const newProps = Object.assign({}, headers.properties[h], { required })
return Object.assign({}, acc, { [h]: newProps })
}, {})
return getHeaderParams(parameters, headerProperties)
}
Object.keys(headers).forEach(h =>
parameters.push({
name: h,
in: 'header',
required: headers[h].required,
description: headers[h].description,
type: headers[h].type
})
)
}
function genResponse (response) {
// if the user does not provided an out schema
if (!response) {
return { 200: { description: 'Default Response' } }
}
// remove previous references
response = Object.assign({}, response)
Object.keys(response).forEach(key => {
if (response[key].type) {
var rsp = response[key]
var description = response[key].description
var headers = response[key].headers
response[key] = {
schema: rsp
}
response[key].description = description || 'Default Response'
if (headers) response[key].headers = headers
}
if (!response[key].description) {
response[key].description = 'Default Response'
}
})
return response
}
// The swagger standard does not accept the url param with ':'
// so '/user/:id' is not valid.
// This function converts the url in a swagger compliant url string
// => '/user/{id}'
function formatParamUrl (url) {
var start = url.indexOf('/:')
if (start === -1) return url
var end = url.indexOf('/', ++start)
if (end === -1) {
return url.slice(0, start) + '{' + url.slice(++start) + '}'
} else {
return formatParamUrl(url.slice(0, start) + '{' + url.slice(++start, end) + '}' + url.slice(end))
}
}
module.exports = fp(fastifySwagger, {

@@ -293,0 +26,0 @@ fastify: '>=0.39.0',

{
"name": "fastify-swagger",
"version": "0.5.0",
"version": "0.6.0",
"description": "Generate Swagger files automatically for Fastify.",

@@ -24,4 +24,4 @@ "main": "index.js",

"devDependencies": {
"fastify": "^0.43.0",
"standard": "^10.0.3",
"fastify": "^1.1.1",
"standard": "^11.0.0",
"swagger-parser": "^4.0.2",

@@ -28,0 +28,0 @@ "tap": "^11.1.0"

@@ -89,30 +89,50 @@ # fastify-swagger

```
<a name="api"></a>
## API
#### register options
```js
{
swagger: {
info: {
title: String,
description: String,
version: String
},
host: String,
schemes: [ String ],
consumes: [ String ],
produces: [ String ],
securityDefinitions: Object
<a name="register.options"></a>
### register options
<a name="modes"></a>
#### modes
`fastify-swagger` supports two registration modes `dynamic` and `static`:
<a name="mode.dynamic"></a>
##### dynamic
`dynamic` mode is the default one, if you use the plugin this way - swagger specification would be gathered from your routes definitions.
```js
{
swagger: {
info: {
title: String,
description: String,
version: String
},
host: String,
schemes: [ String ],
consumes: [ String ],
produces: [ String ],
securityDefinitions: Object
}
}
}
```
*All the above parameters are optional.*
You can use all the properties of the [swagger specification](https://swagger.io/specification/), if you find anything missing, please open an issue or a pr!
```
<a name="options"></a>
#### swagger options
Calling `fastify.swagger` will return to you a JSON object representing your api, if you pass `{ yaml: true }` to `fastify.swagger`, it will return you a yaml string.
*All the above parameters are optional.*
You can use all the properties of the [swagger specification](https://swagger.io/specification/), if you find anything missing, please open an issue or a pr!
If you pass `{ exposeRoute: true }` the plugin will expose the documentation with the following apis:
Example of the `fastify-swagger` usage in the `dynamic` mode is available [here](examples/dynamic.js).
<a name="mode.static"></a>
##### static
`static` mode should be configured explicitly. In this mode `fastify-swagger` serves given specification, you should craft it yourselfe.
```js
{
mode: 'static',
specification: {
path: './examples/example-static-specification.yaml'
}
}
```
Example of the `fastify-swagger` usage in the `static` mode is available [here](examples/static-file.js).
<a name="additional"></a>
#### additional
If you pass `{ exposeRoute: true }` during the registration the plugin will expose the documentation with the following apis:
| url | description |

@@ -124,9 +144,15 @@ |-------|----------------|

<a name="swagger.options"></a>
### swagger options
Calling `fastify.swagger` will return to you a JSON object representing your api, if you pass `{ yaml: true }` to `fastify.swagger`, it will return you a yaml string.
<a name="hide"></a>
#### Hide a route
### Hide a route
Sometimes you may need to hide a certain route from the documentation, just pass `{ hide: true }` to the schema object inside the route declaration.
#### Security
<a name="security"></a>
### Security
Global security definitions and route level security provide documentation only. It does not implement authentication nor route security for you. Once your authentication is implemented, along with your defined security, users will be able to successfully authenticate and interact with your API using the user interfaces of the documentation.
<a name="anknowledgements"></a>
## Acknowledgements

@@ -138,4 +164,5 @@

<a name="license"></a>
## License
Licensed under [MIT](./LICENSE).
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc