import express from 'express'; import swaggerUi from 'swagger-ui-dist'; import jsonRefParser, {JSONSchema} from '@apidevtools/json-schema-ref-parser'; import oasParser from '@apidevtools/swagger-parser'; // modified from https://github.com/scottie1984/swagger-ui-express // usage: app.use('/api-doc', api.serve(), api.setup()); // the paths property can be split using allOf // further route documentation can be included in the x-doc property export default function api () { // generate apiDoc let apiDoc: JSONSchema = {}; jsonRefParser.bundle('api/api.yaml', (err, doc) => { // parse yaml if (err) throw err; apiDoc = doc; apiDoc.servers.splice(process.env.NODE_ENV === 'production', 1); apiDoc.paths = apiDoc.paths.allOf.reduce((s, e) => Object.assign(s, e)); // bundle routes apiDoc = resolveXDoc(apiDoc); oasParser.validate(apiDoc, (err, api) => { // validate oas schema if (err) { console.error(err); } else { console.info(process.env.NODE_ENV === 'test' ? '' : 'API ok, version ' + api.info.version); } }); }); return [ (req, res, next) => { // serve init js and apiDoc file switch (req.url) { case '/swagger-ui-init.js': res.set('Content-Type', 'application/javascript'); res.send(jsTplString); break; case '/apidoc.json': res.set('Content-Type', 'application/json'); res.send(apiDoc); break; default: next(); } }, // serve swagger files express.static(swaggerUi.getAbsoluteFSPath(), {index: false}), (req, res) => { // serve html file as default res.send(htmlTplString); } ]; } function resolveXDoc (doc) { // resolve x-doc properties recursively Object.keys(doc).forEach(key => { if (doc[key] !== null && doc[key].hasOwnProperty('x-doc')) { // add x-doc to description, is styled via css doc[key].description += '
docs' + doc[key]['x-doc'] + '
'; } else if (typeof doc[key] === 'object' && doc[key] !== null) { // go deeper into recursion doc[key] = resolveXDoc(doc[key]); } }); return doc; } // templates const htmlTplString = ` API documentation
`; const jsTplString = ` window.onload = function() { // Build a system window.ui = SwaggerUIBundle({ url: '/api-doc/apidoc.json', dom_id: '#swagger-ui', deepLinking: true, presets: [ SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset ], plugins: [ SwaggerUIBundle.plugins.DownloadUrl ], layout: 'StandaloneLayout' }); } `;