@openapi-generator-plus/typescript-express-example-server-generator
Version:
An OpenAPI Generator Plus template for a TypeScript API server using Express to output example responses
91 lines (86 loc) • 3.25 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.expressPath = expressPath;
exports.index = index;
const template_utils_1 = require("@openapi-generator-plus/template-utils");
/**
* Convert an operation path (using OpenAPI's `{param}` placeholders) to an
* Express route path (using `:param` placeholders).
*/
function expressPath(path) {
if (!path) {
return path;
}
return path.replace(/\{([-a-zA-Z_]+)\}/g, ':$1');
}
/* A single example response, pushed onto the `defaultResponses` array that the
* handler picks a random entry from. Rendered at column 0 — the caller aligns
* it to the handler body's indentation. */
function pushExample(content, example) {
return `defaultResponses.push({
contentType: "${content.mediaType.mediaType}",
body: ${example.valueString},
})`;
}
/* The handler body for an operation whose default response has examples: pick
* one of the examples at random and send it. */
function exampleResponseBody(defaultResponse) {
const pushes = (0, template_utils_1.each)(defaultResponse.contents, content => (0, template_utils_1.each)(content.examples, example => pushExample(content, example), '\n'), '\n');
return (0, template_utils_1.ts) `
const defaultResponses: { contentType: string, body: string }[] = []
${pushes}
const response = defaultResponses[Math.floor(Math.random() * defaultResponses.length)];
res.set('Content-Type', response.contentType)
res.send(response.body)`;
}
/* The handler body for an operation with no example response to return. */
function unimplementedResponseBody() {
return (0, template_utils_1.ts) `
//TODO
res.status(503).send('Unimplemented')`;
}
function operationHandler(op) {
const body = op.defaultResponse && (0, template_utils_1.hasExamples)(op.defaultResponse) ? exampleResponseBody(op.defaultResponse) : unimplementedResponseBody();
return (0, template_utils_1.ts) `
app.${(0, template_utils_1.lowerCase)(op.httpMethod)}('${expressPath(op.fullPath)}', function(req, res) {
${body}
})`;
}
function operationGroup(group) {
return (0, template_utils_1.ts) `
/* ${group.name} */
${(0, template_utils_1.each)(group.operations, operationHandler, '\n')}
`;
}
/*
* Each group's rendering ends with its own trailing blank line (matching how
* the hbs `{{#each groups}}` body emitted one after every group, including
* the last), so `const options` below is glued directly onto the `${each}`
* interpolation rather than sitting on its own source line — putting it on
* its own line would add a second, spurious blank line before it.
*/
function index(ctx) {
return (0, template_utils_1.ts) `
import express from 'express'
import getopts from 'getopts'
const app = express()
${(0, template_utils_1.each)(ctx.groups, operationGroup)}const options = getopts(process.argv.slice(2), {
alias: {
port: 'p',
},
unknown: (option) => {
console.log(\`Unknown option: \${option}\`)
return false
},
})
const port = options.port || 3000
const server = app.listen(port, function() {
const address = server.address()
if (typeof address === 'string') {
console.log(\`Listening on \${address}\`)
} else if (address) {
console.log(\`Listening on \${address.port}\`)
}
})
`;
}