UNPKG

express-oas-generator

Version:

Module to automatically generate OpenAPI (Swagger) specification for existing ExpressJS 4.x REST API applications

320 lines (265 loc) 10.4 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>lib/processors.js - Documentation</title> <script src="scripts/prettify/prettify.js"></script> <script src="scripts/prettify/lang-css.js"></script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify.css"> <link type="text/css" rel="stylesheet" href="styles/jsdoc.css"> <script src="scripts/nav.js" defer></script> <meta name="viewport" content="width=device-width, initial-scale=1.0"> </head> <body> <input type="checkbox" id="nav-trigger" class="nav-trigger" /> <label for="nav-trigger" class="navicon-button x"> <div class="navicon"></div> </label> <label for="nav-trigger" class="overlay"></label> <nav > <h2><a href="index.html">Home</a></h2><h2><a href="https://github.com/mpashkovskiy/express-oas-generator" target="_blank" class="menu-item" >Source code</a></h2><h2><a href="https://github.com/mpashkovskiy/express-oas-generator/issues" target="_blank" class="menu-item" >Issues</a></h2><h3>Modules</h3><ul><li><a href="module-index.html">index</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-index.html#~getMethod">getMethod</a></li><li data-type='method' style='display: none;'><a href="module-index.html#~getPathKey">getPathKey</a></li><li data-type='method' style='display: none;'><a href="module-index.html#~getSpec">getSpec</a></li><li data-type='method' style='display: none;'><a href="module-index.html#~handleRequests">handleRequests</a></li><li data-type='method' style='display: none;'><a href="module-index.html#~handleResponses">handleResponses</a></li><li data-type='method' style='display: none;'><a href="module-index.html#~init">init</a></li><li data-type='method' style='display: none;'><a href="module-index.html#~patchSpec">patchSpec</a></li><li data-type='method' style='display: none;'><a href="module-index.html#~serveApiDocs">serveApiDocs</a></li><li data-type='method' style='display: none;'><a href="module-index.html#~setPackageInfoPath">setPackageInfoPath</a></li><li data-type='method' style='display: none;'><a href="module-index.html#~updateSchemesAndHost">updateSchemesAndHost</a></li><li data-type='method' style='display: none;'><a href="module-index.html#~updateSpecFromPackage">updateSpecFromPackage</a></li></ul></li><li><a href="module-lib_processors.html">lib/processors</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-lib_processors.html#.processBody">processBody</a></li><li data-type='method' style='display: none;'><a href="module-lib_processors.html#.processHeaders">processHeaders</a></li><li data-type='method' style='display: none;'><a href="module-lib_processors.html#.processPath">processPath</a></li><li data-type='method' style='display: none;'><a href="module-lib_processors.html#.processQuery">processQuery</a></li><li data-type='method' style='display: none;'><a href="module-lib_processors.html#.processResponse">processResponse</a></li><li data-type='method' style='display: none;'><a href="module-lib_processors.html#~appendChunkIfNeeded">appendChunkIfNeeded</a></li><li data-type='method' style='display: none;'><a href="module-lib_processors.html#~isCompressed">isCompressed</a></li><li data-type='method' style='display: none;'><a href="module-lib_processors.html#~updateProduces">updateProduces</a></li><li data-type='method' style='display: none;'><a href="module-lib_processors.html#~updateResponses">updateResponses</a></li><li data-type='method' style='display: none;'><a href="module-lib_processors.html#~updateSecurity">updateSecurity</a></li><li data-type='method' style='display: none;'><a href="module-lib_processors.html#~updateSecurityDefinitions">updateSecurityDefinitions</a></li></ul></li><li><a href="module-lib_utils.html">lib/utils</a><ul class='methods'><li data-type='method' style='display: none;'><a href="module-lib_utils.html#.getSchema">getSchema</a></li><li data-type='method' style='display: none;'><a href="module-lib_utils.html#.getType">getType</a></li><li data-type='method' style='display: none;'><a href="module-lib_utils.html#.sortObject">sortObject</a></li><li data-type='method' style='display: none;'><a href="module-lib_utils.html#~fillExamples">fillExamples</a></li></ul></li></ul> </nav> <div id="main"> <h1 class="page-title">lib/processors.js</h1> <section> <article> <pre class="prettyprint source linenums"><code>/** * @fileOverview processors * @module lib/processors */ const generateSchema = require('generate-schema'); const utils = require('./utils'); /** * * @param req * @param method * @param pathKey */ module.exports.processPath = (req, method, pathKey) => { if (pathKey.indexOf('{') === -1) { return; } const pathRegexp = pathKey.replace(/{([^/]+)}/g, '(.+)?'); const matches = req.url.match(pathRegexp); if (!matches) { return; } let i = 1; method.parameters.forEach(p => { if (p.in === 'path') { p.type = utils.getType(matches[i]); p.example = p.type === 'string' ? matches[i] : Number(matches[i]); i += 1; } }); }; /** * * @param method * @param headerName */ function updateSecurity(method, headerName) { method.security = method.security || []; if (method.security.map(s => Object.keys(s)[0]).indexOf(headerName) === -1) { const obj = {}; obj[headerName] = []; method.security.push(obj); } } /** * * @param spec * @param headerName */ function updateSecurityDefinitions(spec, headerName) { spec.securityDefinitions = spec.securityDefinitions || {}; spec.securityDefinitions[headerName] = { name: headerName, in: 'header', type: 'apiKey', }; } /** * * @param req * @param method * @param spec */ module.exports.processHeaders = (req, method, spec) => { Object .keys(req.headers) .filter(h => h.toLowerCase() === 'authorization' || h.toLowerCase().startsWith('x-')) .forEach(h => { if (h.toLowerCase() === 'authorization') { method.responses = method.responses || {}; method.responses[401] = { description: 'Unauthorized' }; } updateSecurity(method, h); updateSecurityDefinitions(spec, h); }); }; /** * * @param req * @param method */ module.exports.processBody = (req, method) => { if (!req.body || Object.keys(req.body).length === 0) { return; } method.parameters = method.parameters || []; if (method.parameters.filter(p => p.in === 'body').length !== 0) { return; } method.parameters.push({ in: 'body', name: 'body', required: true, schema: utils.getSchema(req.body), }); }; /** * * @param req * @param method */ module.exports.processQuery = (req, method) => { const params = req.query; if (!params || Object.keys(params).length === 0) { return; } const props = generateSchema.json(params).properties; for (const p in props) { if (method.parameters.filter(param => param.name === p).length !== 0) { continue; } const param = props[p]; param.name = p; param.in = 'query'; param.example = params[p]; if (param.type === 'array') { param.collectionFormat = 'multi'; } else if (param.type === 'string') { param.type = utils.getType(params[p]); } method.parameters.push(param); } }; /** * * @param res * @param method */ function updateProduces(res, method) { let contentType = res.get('content-type'); if (!contentType) { return; } contentType = contentType.split(';')[0]; method.produces = method.produces || []; if (method.produces.indexOf(contentType) === -1) { method.produces.push(contentType); } } /** * * @param res * @param method * @param chunks */ function updateResponses(res, method, chunks) { method.responses = method.responses || {}; method.responses[res.statusCode] = {}; const contentType = res.get('content-type'); if (!contentType || contentType.indexOf('json') === -1 &amp;&amp; contentType.indexOf('text') === -1) { return; } let body = ''; let schema; try { body = Buffer.concat(chunks).toString('utf8'); body = JSON.parse(body); schema = utils.getSchema(body); } catch (ex) { const type = utils.getType(body); schema = { type: type, example: type === 'string' ? body : Number(body) }; } method.responses[res.statusCode].schema = schema; } /** * * @param res * @param method * @param chunks * @param chunk */ function appendChunkIfNeeded(res, method, chunks, chunk) { if (method.responses &amp;&amp; method.responses[res.statusCode]) { return; } if (!chunk) { return; } chunks.push(new Buffer(chunk)); } /** * * @param res * @returns {boolean} */ function isCompressed(res) { const headers = res.getHeaders ? res.getHeaders() : res.headers(); return ['gzip', 'compress', 'deflate'].indexOf(headers['content-encoding']) !== -1; } /** * * @param res * @param method */ module.exports.processResponse = (res, method) => { const oldWrite = res.write; const oldEnd = res.end; const chunks = []; res.write = function(chunk) { try { if (!isCompressed(res)) { appendChunkIfNeeded(res, method, chunks, chunk); } } finally { oldWrite.apply(res, arguments); } }; res.end = function(chunk) { try { if (!isCompressed(res)) { appendChunkIfNeeded(res, method, chunks, chunk); updateProduces(res, method); if (!method.responses || !method.responses[res.statusCode]) { updateResponses(res, method, chunks); } } } finally { oldEnd.apply(res, arguments); } }; }; </code></pre> </article> </section> </div> <br class="clear"> <footer> Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.3</a> on Fri Dec 27 2019 14:41:23 GMT+0200 (Eastern European Standard Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme. </footer> <script>prettyPrint();</script> <script src="scripts/polyfill.js"></script> <script src="scripts/linenumber.js"></script> <script src="scripts/collapse.js" defer></script> </body> </html>