UNPKG

fastify-swagger

Version:

Serve Swagger/OpenAPI documentation for Fastify, supporting dynamic generation

98 lines (77 loc) 3.34 kB
'use strict' const path = require('path') const fs = require('fs') const yaml = require('js-yaml') module.exports = function (fastify, opts, done) { if (!opts.specification) return done(new Error('specification is missing in the module options')) if (typeof opts.specification !== 'object') return done(new Error('specification is not an object')) let swaggerObject = {} if (!opts.specification.path && !opts.specification.document) { return done(new Error('both specification.path and specification.document are missing, should be path to the file or swagger document spec')) } else if (opts.specification.path) { if (typeof opts.specification.path !== 'string') return done(new Error('specification.path is not a string')) if (!fs.existsSync(path.resolve(opts.specification.path))) return done(new Error(`${opts.specification.path} does not exist`)) const extName = path.extname(opts.specification.path).toLowerCase() if (['.yaml', '.json'].indexOf(extName) === -1) return done(new Error("specification.path extension name is not supported, should be one from ['.yaml', '.json']")) if (opts.specification.postProcessor && typeof opts.specification.postProcessor !== 'function') return done(new Error('specification.postProcessor should be a function')) if (opts.specification.baseDir && typeof opts.specification.baseDir !== 'string') return done(new Error('specification.baseDir should be string')) if (!opts.specification.baseDir) { opts.specification.baseDir = path.resolve(path.dirname(opts.specification.path)) } else { while (opts.specification.baseDir.endsWith('/')) { opts.specification.baseDir = opts.specification.baseDir.slice(0, -1) } } // read const source = fs.readFileSync( path.resolve(opts.specification.path), 'utf8' ) switch (extName) { case '.yaml': swaggerObject = yaml.load(source) break case '.json': swaggerObject = JSON.parse(source) break } // apply postProcessor, if one was passed as an argument if (opts.specification.postProcessor) { swaggerObject = opts.specification.postProcessor(swaggerObject) } } else { if (typeof opts.specification.document !== 'object') return done(new Error('specification.document is not an object')) swaggerObject = opts.specification.document } fastify.decorate('swagger', swagger) if (opts.exposeRoute === true) { const options = { prefix: opts.routePrefix || '/documentation', uiConfig: opts.uiConfig || {}, initOAuth: opts.initOAuth || {}, baseDir: opts.specification.baseDir, staticCSP: opts.staticCSP, transformStaticCSP: opts.transformStaticCSP } fastify.register(require('../routes'), options) } 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 } if (opts && opts.yaml) { const swaggerString = yaml.dump(swaggerObject, { skipInvalid: true }) cache.swaggerString = swaggerString return swaggerString } cache.swaggerObject = swaggerObject return swaggerObject } done() }