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
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 && 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 && 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>