@chezearth/swagger-node-runner
Version:
Swagger loader and middleware utilities
141 lines (108 loc) • 5.54 kB
JavaScript
'use strict';
var debug = require('debug')('swagger:swagger_router');
var path = require('path');
var assert = require('assert');
var SWAGGER_ROUTER_CONTROLLER = 'x-swagger-router-controller';
var CONTROLLER_INTERFACE_TYPE = 'x-controller-interface';
var allowedCtrlInterfaces = ["middleware", "pipe", "auto-detect"];
var util = require('util');
module.exports = function create(fittingDef, bagpipes) {
debug('config: %j', fittingDef);
assert(Array.isArray(fittingDef.controllersDirs), 'controllersDirs must be an array');
assert(Array.isArray(fittingDef.mockControllersDirs), 'mockControllersDirs must be an array');
if (!fittingDef.controllersInterface) fittingDef.controllersInterface = "middleware";
assert( ~allowedCtrlInterfaces.indexOf(fittingDef.controllersInterface),
'value in swagger_router config.controllersInterface - can be one of ' + allowedCtrlInterfaces + ' but got: ' + fittingDef.controllersInterface
);
var swaggerNodeRunner = bagpipes.config.swaggerNodeRunner;
swaggerNodeRunner.api.getOperations().forEach(function(operation) {
var interfaceType =
operation.controllerInterface =
operation.definition[CONTROLLER_INTERFACE_TYPE] ||
operation.pathObject.definition[CONTROLLER_INTERFACE_TYPE] ||
swaggerNodeRunner.api.definition[CONTROLLER_INTERFACE_TYPE] ||
fittingDef.controllersInterface;
assert( ~allowedCtrlInterfaces.indexOf(interfaceType),
'whenever provided, value of ' + CONTROLLER_INTERFACE_TYPE + ' directive in openapi doc must be one of ' + allowedCtrlInterfaces + ' but got: ' + interfaceType);
})
var appRoot = swaggerNodeRunner.config.swagger.appRoot;
var dependencies = swaggerNodeRunner.config.swagger.dependencies
var mockMode = !!fittingDef.mockMode || !!swaggerNodeRunner.config.swagger.mockMode;
var controllersDirs = mockMode ? fittingDef.mockControllersDirs : fittingDef.controllersDirs;
controllersDirs = controllersDirs.map(function(dir) {
return path.resolve(appRoot, dir);
});
var controllerFunctionsCache = {};
return function swagger_router(context, cb) {
debug('exec');
var operation = context.request.swagger.operation;
var controllerName = operation[SWAGGER_ROUTER_CONTROLLER] || operation.pathObject[SWAGGER_ROUTER_CONTROLLER];
var controller;
if (controllerName in controllerFunctionsCache) {
debug('controller in cache', controllerName);
controller = controllerFunctionsCache[controllerName];
} else if (controllerName) {
debug('loading controller %s from fs: %s', controllerName, controllersDirs);
for (var i = 0; i < controllersDirs.length; i++) {
var controllerPath = path.resolve(controllersDirs[i], controllerName);
try {
var ctrlObj = require(controllerPath)
controller = dependencies && typeof ctrlObj === 'function' ? ctrlObj(dependencies) : ctrlObj
controllerFunctionsCache[controllerName] = controller;
debug('controller found', controllerPath);
break;
} catch (err) {
if (!mockMode && i === controllersDirs.length - 1) {
return cb(err);
}
debug('controller not in', controllerPath);
}
}
}
if (controller) {
var operationId = operation.definition.operationId || context.request.method.toLowerCase();
var ctrlType =
operation.definition['x-controller-type'] ||
operation.pathObject.definition['x-controller-type'] ||
operation.pathObject.api.definition['x-controller-type'];
var controllerFunction = controller[operationId];
if (controllerFunction && typeof controllerFunction === 'function') {
if (operation.controllerInterface == 'auto-detect') {
operation.controllerInterface =
controllerFunction.length == 3
? 'middleware'
: 'pipe';
debug("auto-detected interface-type for operation '%s' at [%s] as '%s'", operationId, operation.pathToDefinition, operation.controllerInterface)
}
debug('running controller, as %s', operation.controllerInterface);
return operation.controllerInterface == 'pipe'
? controllerFunction(context, cb)
: controllerFunction(context.request, context.response, cb);
}
var msg = util.format('Controller %s doesn\'t export handler function %s', controllerName, operationId);
if (mockMode) {
debug(msg);
} else {
return cb(new Error(msg));
}
}
if (mockMode) {
var statusCode = parseInt(context.request.get('_mockreturnstatus')) || 200;
var mimetype = context.request.get('accept') || 'application/json';
var response = operation.getResponse(statusCode) || operation.getResponse('default');
var mock = response.getExample(mimetype);
if (mock) {
debug('returning mock example value', mock);
} else {
var operationResponse = operation.getResponse(statusCode) || operation.getResponse('default');
mock = operationResponse.getSample();
debug('returning mock sample value', mock);
}
context.headers['Content-Type'] = mimetype;
context.statusCode = statusCode;
return cb(null, mock);
}
// for completeness, we should never actually get here
cb(new Error(util.format('No controller found for %s in %j', controllerName, controllersDirs)));
}
};