Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public class NodeJSExpressServerCodegen extends DefaultCodegen implements Codege

protected String apiVersion = "1.0.0";
protected String defaultServerPort = "8080";
protected String implFolder = "service";
protected String implFolder = "services";
protected String projectName = "openapi-server";
protected String exportedName;

Expand Down Expand Up @@ -91,17 +91,16 @@ public NodeJSExpressServerCodegen() {

// utils folder
supportingFiles.add(new SupportingFile("utils" + File.separator + "openapiRouter.mustache", "utils", "openapiRouter.js"));
supportingFiles.add(new SupportingFile("utils" + File.separator + "swaggerRouter.mustache", "utils", "swaggerRouter.js"));
supportingFiles.add(new SupportingFile("utils" + File.separator + "writer.mustache", "utils", "writer.js"));

// controllers folder
supportingFiles.add(new SupportingFile("service" + File.separator + "test.mustache", "controllers", "TestController.js"));
supportingFiles.add(new SupportingFile("controllers" + File.separator + "test.mustache", "controllers", "TestController.js"));
supportingFiles.add(new SupportingFile("controllers" + File.separator + "index.mustache", "controllers", "index.js"));
supportingFiles.add(new SupportingFile("controllers" + File.separator + "Controller.mustache", "controllers", "Controller.js"));
// service folder
supportingFiles.add(new SupportingFile("service" + File.separator + "test.mustache", "service", "TestService.js"));
supportingFiles.add(new SupportingFile("service" + File.separator + "index.mustache", "service", "index.js"));
supportingFiles.add(new SupportingFile("service" + File.separator + "Service.mustache", "service", "Service.js"));
supportingFiles.add(new SupportingFile("services" + File.separator + "test.mustache", "services", "TestService.js"));
supportingFiles.add(new SupportingFile("services" + File.separator + "index.mustache", "services", "index.js"));
supportingFiles.add(new SupportingFile("services" + File.separator + "Service.mustache", "services", "Service.js"));

// do not overwrite if the file is already present
writeOptional(outputFolder, new SupportingFile("package.mustache", "", "package.json"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const Controller = require('./Controller');
class {{{classname}}}Controller {
constructor(Service) {
this.service = Service;
}

{{#operations}}
{{#operation}}
Expand All @@ -13,5 +14,5 @@ class {{{classname}}}Controller {
{{/operation}}
}

module.exports = {{classname}};
module.exports = {{classname}}Controller;
{{/operations}}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const logger = require('../logger');

class Controller {
static sendResponse(response, payload) {
/**
Expand All @@ -23,7 +25,26 @@ class Controller {
}
}

static collectFiles(request) {
logger.info('Checking if files are expected in schema');
if (request.openapi.schema.requestBody !== undefined) {
const [contentType] = request.headers['content-type'].split(';');
if (contentType === 'multipart/form-data') {
const contentSchema = request.openapi.schema.requestBody.content[contentType].schema;
Object.entries(contentSchema.properties).forEach(([name, property]) => {
if (property.type === 'string' && ['binary', 'base64'].indexOf(property.format) > -1) {
request.body[name] = request.files.find(file => file.fieldname === name);
}
});
} else if (request.openapi.schema.requestBody.content[contentType] !== undefined
&& request.files !== undefined) {
[request.body] = request.files;
}
}
}

static collectRequestParams(request) {
this.collectFiles(request);
const requestParams = {};
if (request.openapi.schema.requestBody !== undefined) {
requestParams.body = request.body;
Expand All @@ -41,13 +62,6 @@ class Controller {
static async handleRequest(request, response, serviceOperation) {
try {
const serviceResponse = await serviceOperation(this.collectRequestParams(request));
// let serviceResponse;
// this.collectRequestParams(request);
// if (request.openapi.schema.requestBody !== undefined) {
// serviceResponse = await serviceOperation(request.body);
// } else {
// serviceResponse = await serviceOperation(request.openapi.requestParams);
// }
Controller.sendResponse(response, serviceResponse);
} catch (error) {
Controller.sendError(response, error);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
const Controller = require('./Controller');
const Service = require('../services/Service');

class TestController {
constructor(Service) {
this.service = Service;
}
const testItems = require('../tests/testFiles/testItems.json');

class TestService {
static testGetController() {
return new Promise(
async (resolve, reject) => {
try {
resolve(Service.successResponse(
testItems,
200,
));
} catch (e) {
const message = e.getMessage() || 'Could not get items. Server error';
reject(Service.rejectResponse(message, 500));
}
},
);

sendResponse(request, response) {
response.status(200);
Expand Down Expand Up @@ -56,4 +69,4 @@ class TestController {
}
}

module.exports = Test;
module.exports = TestController;
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,60 @@ const cors = require('cors');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const { OpenApiValidator } = require('express-openapi-validator');
const swaggerRouter = require('./utils/swaggerRouter');

// const pathToRegexp = require('path-to-regexp');
const openapiRouter = require('./utils/openapiRouter');
const logger = require('./logger');

class ExpressServer {
constructor(port, openApiYaml) {
this.port = port;
this.app = express();
this.schema = openApiYaml;
this.openApiPath = openApiYaml;
this.schema = yamljs.load(openApiYaml);
// this.middleware = new Middleware(this.app);
this.setupMiddleware();
}

// handleIncomingMedia(request) {
// console.log(this.apiValidator);
// const incomingMedia = request.headers['content-type'].split(';')[0];
// logger.info(`checking access for media type ${incomingMedia}`);
// const currentServer = this.schema.servers.find(
// server => server.url.indexOf(request.headers.host) > -1,
// );
// const currentServerUrl = currentServer.url.substr(currentServer.url.indexOf('://') + 3);
// // const path = `${request.headers.host}${request.originalUrl}`;
// const requestPath = `${request.headers.host}${request.originalUrl}`.substr(currentServerUrl.length);
// this.allowedMedia.forEach((permissions, path) => {
// console.log(path, permissions);
// const keys = [];
// const regex = pathToRegexp(path, keys);
// const matches = regex.exec(requestPath);
// console.log(matches);
// });
// // this.allowedMedia.find((instance) => {
// // const keys = [];
// // const regex = pathToRegexp(Object.keys(instance)[0], keys);
// // return instance.path === regex;
// // });
//
// logger.info(`analysing incoming media. content type: ${request.headers['content-type']}`); '';
// logger.info(this.schema.paths[request.url]);
// logger.info(this.schema);
// }

setupMiddleware() {
// this.setupAllowedMedia();
this.app.use(cors());
this.app.use(bodyParser.json());
this.app.use(express.json());
this.app.use(express.urlencoded({ extended: false }));
this.app.use(cookieParser());
this.app.get('/spec', express.static(this.schema));
this.app.use('/api-docs', swaggerUI.serve, swaggerUI.setup(yamljs.load(this.schema)));
// this.app.use(bodyParser.raw({
// type: (req => this.handleIncomingMedia(req)),
// }));
this.app.get('/spec', express.static(this.openApiPath));
this.app.use('/api-docs', swaggerUI.serve, swaggerUI.setup(this.schema));
this.app.get('/login-redirect', (req, res) => {
res.status(200);
res.json(req.query);
Expand All @@ -35,21 +69,9 @@ class ExpressServer {
res.json(req.query);
});
new OpenApiValidator({
apiSpecPath: this.schema,
apiSpecPath: this.openApiPath,
}).install(this.app);
this.app.use(swaggerRouter());
// this.middleware.init(this.schema, (err) => {
// if (err) {
// console.error(err);
// }
// });
// this.app.use(
// // this.middleware.metadata(),
// // this.middleware.CORS(),
// // this.middleware.parseRequest(),
// // this.middleware.validateRequest(),
// // ('/api-docs', swaggerUI.serve, swaggerUI.setup(this.swaggerJson)),
// );
this.app.use(openapiRouter());
this.app.get('/', (req, res) => {
res.status(200);
res.end('Hello World');
Expand Down Expand Up @@ -96,5 +118,25 @@ class ExpressServer {
console.log(`Server on port ${this.port} shut down`);
}
}

setupAllowedMedia() {
this.allowedMedia = new Map();
logger.info('Setting up allowed media types according to schema deifnition');
Object.entries(this.schema.paths).forEach(([pathName, pathOperation]) => {
const pathMedia = {};
['post', 'put', 'patch'].forEach((method) => {
if (pathOperation[method] !== undefined
&& pathOperation[method].requestBody !== undefined) {
pathMedia[method] = [];
Object.keys(pathOperation[method].requestBody.content).forEach((mediaType) => {
pathMedia[method].push(mediaType);
});
}
});
if (Object.keys(pathMedia).length > 0) {
this.allowedMedia.set(pathName, pathMedia);
}
});
}
}
module.exports = ExpressServer;
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class {{{classname}}}Service {
* returns {{{returnType}}}
{{/returnType}}
**/
static.{{{operationId}}}({ {{#allParams}}{{paramName}}{{#hasMore}},{{/hasMore}}{{/allParams}} }) {
static {{{operationId}}}({{#allParams}}{{#-first}}{ {{/-first}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{#-last}} }{{/-last}}{{/allParams}}) {
return new Promise(
async (resolve) => {
try {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,67 @@
class OpenapiRouter {
constructor(openApiDoc) {
this.apiDoc = openApiDoc;
}
const logger = require('../logger');
const controllers = require('../controllers');
const Services = require('../services');

loadSchemas() {
console.log(this.apiDoc);
}
function handleError(err, request, response, next) {
logger.error(err);
const code = err.code || 400;
response.status(code);
response.error = err;
next(JSON.stringify({
code,
error: err,
}));
}

module.exports = OpenapiRouter;
/**
* The purpose of this route is to collect the request variables as defined in the
* OpenAPI document and pass them to the handling controller as another Express
* middleware. All parameters are collected in the requet.swagger.values key-value object
*
* The assumption is that security handlers have already verified and allowed access
* to this path. If the business-logic of a particular path is dependant on authentication
* parameters (e.g. scope checking) - it is recommended to define the authentication header
* as one of the parameters expected in the OpenAPI/Swagger document.
*
* Requests made to paths that are not in the OpernAPI scope
* are passed on to the next middleware handler.
* @returns {Function}
*/
function openApiRouter() {
return async (request, response, next) => {
try {
/**
* This middleware runs after a previous process have applied an openapi object
* to the request.
* If none was applied This is because the path requested is not in the schema.
* If there's no openapi object, we have nothing to do, and pass on to next middleware.
*/
if (request.openapi === undefined
|| request.openapi.schema === undefined
) {
next();
return;
}
// request.swagger.paramValues = {};
// request.swagger.params.forEach((param) => {
// request.swagger.paramValues[param.name] = getValueFromRequest(request, param);
// });
const controllerName = request.openapi.schema['x-openapi-router-controller'];
const serviceName = request.openapi.schema['x-openapi-router-service'];
if (!controllers[controllerName] || controllers[controllerName] === undefined) {
handleError(`request sent to controller '${controllerName}' which has not been defined`,
request, response, next);
} else {
const apiController = new controllers[controllerName](Services[serviceName]);
const controllerOperation = request.openapi.schema.operationId;
await apiController[controllerOperation](request, response, next);
}
} catch (error) {
console.error(error);
const err = { code: 500, error: error.message };
handleError(err, request, response, next);
}
};
}

module.exports = openApiRouter;

This file was deleted.

Loading