Skip to content

Commit

Permalink
Merge pull request #65 from osher/patch-1
Browse files Browse the repository at this point in the history
resolving controller-interface type
  • Loading branch information
theganyo authored Oct 31, 2016
2 parents a44711b + 6ec101f commit 833c3b1
Show file tree
Hide file tree
Showing 12 changed files with 381 additions and 7 deletions.
1 change: 1 addition & 0 deletions fittings/swagger_cors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./cors');
40 changes: 37 additions & 3 deletions fittings/swagger_router.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ 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) {
Expand All @@ -12,8 +14,25 @@ module.exports = function create(fittingDef, bagpipes) {

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

Expand Down Expand Up @@ -62,12 +81,27 @@ module.exports = function create(fittingDef, bagpipes) {

if (controller) {

var operationId = operation.definition['operationId'] || context.request.method.toLowerCase();
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') {
debug('running controller');
return controllerFunction(context.request, context.response, cb);
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);
Expand Down
2 changes: 1 addition & 1 deletion lib/connect_middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ function Middleware(runner) {
};

context._finish = function finishConnect(ignore1, ignore2) { // must have arity of 2

debugContent("exec", context.error);
if (context.error) { return next(context.error); }

try {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports = {
pipeInterface: pipeInterface,
middlewareInterface: middlewareInterface
}

function pipeInterface(ctx, next) {
ctx.statusCode = 200;
ctx.headers = {
'content-type': 'application/json',
'x-interface': 'pipe'
};
next(null, { interface: 'pipe' });
}

function middlewareInterface(req, res, next) {
res.setHeader('x-interface', 'middleware');
res.json({ interface: "middleware" });
}
56 changes: 56 additions & 0 deletions test/assets/project/api/pipes/hello_world.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
'use strict';
var util = require('util');

module.exports = {
hello: hello,
hello_body: hello_body,
hello_file: hello_file,
get: hello,
self_multiple_writes : self_multiple_writes,
hello_text_body: hello_text_body
};

function hello(ctx, next) {
var req = ctx.request;
var name = req.swagger.params.name.value || 'stranger';
var hello = { message: util.format('Hello, %s!', name) };
ctx.statusCode = 200;
ctx.headers = { 'content-type' : 'application/json' };
next(null, hello)
}

function hello_body(ctx, next) {
var req = ctx.request;
var name = req.swagger.params.nameRequest.value.name || 'stranger';
var hello = { message: util.format('Hello, %s!', name) };
ctx.statusCode = 200;
ctx.headers = {};
next(null, hello)
}

function hello_file(ctx, next) {
var req = ctx.request;
var name = req.swagger.params.name.value || 'stranger';
var file = req.swagger.params.example_file.value;
var hello = { message: util.format('Hello, %s!', name) };
ctx.statusCode = 200;
ctx.headers = {};
next(null, hello)
}

function self_multiple_writes(ctx, next) {
var res = ctx.response;
res.write('hello');
res.write('world');
res.end('yo');
next();
}

function hello_text_body(ctx, next) {
var req = ctx.request;
var name = req.swagger.params.name.value || 'stranger';
var hello = { message: util.format('Hello, %s!', name) };
ctx.statusCode = 200;
ctx.headers = {};
next(null, hello)
}
39 changes: 39 additions & 0 deletions test/assets/project/api/swagger/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,45 @@ paths:
content-type:
type: integer
schema: {}
/controller_interface_auto_detected_as_pipe:
x-swagger-router-controller: overrides_ctrl_interface_pipe
x-controller-interface: auto-detect
get:
description: well, what do you know...
operationId: pipeInterface
responses:
200:
description: Whatever
schema: {}
/controller_interface_auto_detected_as_middleware:
x-swagger-router-controller: overrides_ctrl_interface_pipe
x-controller-interface: auto-detect
get:
description: well, what do you know...
operationId: middlewareInterface
responses:
200:
description: Whatever
schema: {}
/controller_interface_on_path_cascades:
x-swagger-router-controller: overrides_ctrl_interface_pipe
x-controller-interface: pipe
get:
operationId: pipeInterface
responses:
200:
description: Whatever
schema: {}
/controller_interface_on_operation_cascades:
x-swagger-router-controller: overrides_ctrl_interface_pipe
x-controller-interface: pipe
get:
x-controller-interface: middleware
operationId: middlewareInterface
responses:
200:
description: Whatever
schema: {}
definitions:
HelloWorldResponse:
type: object
Expand Down
39 changes: 39 additions & 0 deletions test/assets/project/config_auto/default.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# values in the swagger hash are system configuration for swagger-node
swagger:

fittingsDirs: [ api/fittings ]
defaultPipe: null
swaggerControllerPipe: swagger_controllers # defines the standard processing pipe for controllers

# values defined in the bagpipes key are the bagpipes pipes and fittings definitions
# (see https://github.com/apigee-127/bagpipes)
bagpipes:

_router:
name: swagger_router
mockMode: false
mockControllersDirs: [ api/mocks ]
controllersDirs: [ api/controllers ]
controllersInterface: auto-detect

_swagger_validate:
name: swagger_validator
validateResponse: true

_swagger_security:
name: swagger_security
securityHandlersModule: api/helpers/securityHandlers

# pipe for all swagger-node controllers
swagger_controllers:
- onError: json_error_handler
- cors
- swagger_params_parser
- _swagger_security
- _swagger_validate
- express_compatibility
- _router

# pipe to serve swagger (endpoint is in swagger.yaml)
swagger_raw:
name: swagger_raw
39 changes: 39 additions & 0 deletions test/assets/project/config_pipe/default.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# values in the swagger hash are system configuration for swagger-node
swagger:

fittingsDirs: [ node_modules, api/fittings ]
defaultPipe: null
swaggerControllerPipe: swagger_controllers # defines the standard processing pipe for controllers

# values defined in the bagpipes key are the bagpipes pipes and fittings definitions
# (see https://github.com/apigee-127/bagpipes)
bagpipes:

_router:
name: swagger_router
mockMode: false
mockControllersDirs: [ api/mocks ]
controllersDirs: [ api/pipes ]
controllersInterface: pipe

_swagger_validate:
name: swagger_validator
validateResponse: true

_swagger_security:
name: swagger_security
securityHandlersModule: api/helpers/securityHandlers

# pipe for all swagger-node controllers
swagger_controllers:
- onError: json_error_handler
- swagger_cors
- swagger_params_parser
- _swagger_security
- _swagger_validate
- express_compatibility
- _router

# pipe to serve swagger (endpoint is in swagger.yaml)
swagger_raw:
name: swagger_raw
2 changes: 1 addition & 1 deletion test/fittings/swagger_raw.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('swagger_raw', function() {
delete(filteredSwagger.paths['/invalid_header']);

// hokey algorithm, but at least it's different than the one it's testing
var OMIT = ['x-swagger-router-controller', 'x-swagger-pipe', 'x-hidden', 'x-private'];
var OMIT = ['x-swagger-router-controller', 'x-swagger-pipe', 'x-hidden', 'x-private', 'x-controller-interface'];
_.forEach(filteredSwagger.paths, function(element, name) {
filteredSwagger.paths[name] = _.omit(element, OMIT);
_.forEach(filteredSwagger.paths[name], function(element, subName) {
Expand Down
Loading

0 comments on commit 833c3b1

Please sign in to comment.