Skip to content

Commit db639dd

Browse files
committed
feat(middleware): change middleware flow to make it more enrich/error based
1 parent 63408fb commit db639dd

File tree

5 files changed

+64
-36
lines changed

5 files changed

+64
-36
lines changed

lib/server_middleware/api.js

+20-12
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
const express = require('express');
22
const url = require('url');
33
const expressBodyParser = require('body-parser');
4-
const { DEFAULT_PARSER_OPTIONS } = require('../utility/body_parser');
5-
const { getControllerFiles, getControllerMiddleware, controllerMappingServerSide } = require('../utility/controllers');
4+
const { DEFAULT_PARSER_OPTIONS } = require('../utility/body_parser');
5+
const { getControllerFiles, getControllerMiddleware, middlewareHandler, controllerMappingServerSide } = require('../utility/controllers');
66

77
/**
88
* Action handler middleware.
99
*
1010
* @param ControllerClass
11-
* @param methodName
11+
* @param actionName
1212
* @param options
1313
* @returns {Function}
1414
*/
15-
function actionHandler(ControllerClass, methodName, options) {
15+
function actionHandler(ControllerClass, actionName, options) {
1616
return function (req, res, next) {
1717
const controller = new ControllerClass(req);
1818

19-
return Promise.resolve(controller[methodName]({params: req.params, body: req.body, query: req.query}))
19+
return Promise.resolve(controller[actionName]({params: req.params, body: req.body, query: req.query}))
2020
.then(function (result) {
2121
res.result = options.successHandler(result, req);
2222
next();
@@ -37,16 +37,20 @@ function createControllerRouter(controllerFile, options) {
3737
const ControllerClass = require(controllerFile);
3838
const routes = ControllerClass.ROUTES || {};
3939

40-
Object.keys(routes).forEach(function (methodName) {
41-
if (ControllerClass.prototype[methodName]) {
42-
const {path, verb} = routes[methodName];
40+
Object.keys(routes).forEach(function (actionName) {
41+
if (ControllerClass.prototype[actionName]) {
42+
const {path, verb} = routes[actionName];
4343
const controllerMiddleware = getControllerMiddleware(ControllerClass);
4444

4545
router[verb.toLowerCase()](
4646
path,
47-
...controllerMiddleware.all, // Controller middleware for all actions
48-
...(controllerMiddleware.actions && controllerMiddleware.actions[methodName] || []), // Action only middleware
49-
actionHandler(ControllerClass, methodName, options) // Handle controller action method.
47+
function (req, res, next) {
48+
return middlewareHandler(controllerMiddleware.all, req)
49+
.then(() => middlewareHandler(controllerMiddleware.actions && controllerMiddleware.actions[actionName] || [], req))
50+
.then(() => next())
51+
.catch(next);
52+
},
53+
actionHandler(ControllerClass, actionName, options) // Handle controller action method.
5054
);
5155
}
5256
});
@@ -122,7 +126,11 @@ function injectAPI(options) {
122126

123127
// Middleware for all API routes
124128
if (options.middleware) {
125-
router.use(...(Array.isArray(options.middleware) ? options.middleware : [options.middleware]));
129+
router.use(function (req, res, next) {
130+
return middlewareHandler(options.middleware, req)
131+
.then(() => next())
132+
.catch(next);
133+
});
126134
}
127135

128136
// Inject Controller routes

lib/utility/controllers.js

+34-5
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,19 @@ function controllerMapping(directory, controllerValue) {
9494
return mapping;
9595
}
9696

97+
/**
98+
* Middleware handler for express router.
99+
*
100+
* @param middleware
101+
* @returns {Object}
102+
*/
103+
function middlewareHandler(middleware, req) {
104+
middleware = Array.isArray(middleware) ? middleware : middleware && [middleware] || [];
105+
return Promise.all(middleware.map(function (fn) {
106+
return Promise.resolve(fn(req));
107+
}));
108+
}
109+
97110
/**
98111
* Route Controller mapping for client side api plugin.
99112
*
@@ -118,6 +131,7 @@ function controllerMappingClientSide(directory) {
118131
* @returns {Object}
119132
*/
120133
function controllerMappingServerSide(directory, req, options) {
134+
const apiMiddleware = options.middleware;
121135
let ResponseMiddleware = options.responseMiddleware
122136
? require(options.responseMiddleware.replace(options.aliasKey, options.srcDir))
123137
: null;
@@ -127,13 +141,27 @@ function controllerMappingServerSide(directory, req, options) {
127141
: ResponseMiddleware;
128142

129143
return controllerMapping(options.directory, function (ControllerClass, actionName) {
144+
const controllerMiddleware = getControllerMiddleware(ControllerClass);
145+
130146
return function ({params, body, query} = {}) {
131147
try {
132-
return Promise.resolve(new ControllerClass(req)[actionName]({
133-
params: params || {},
134-
body: body || {},
135-
query: query || {}
136-
}))
148+
return middlewareHandler(apiMiddleware, req)
149+
.then(function () {
150+
return middlewareHandler(controllerMiddleware.all, req);
151+
})
152+
.then(function () {
153+
return middlewareHandler(
154+
controllerMiddleware.actions && controllerMiddleware.actions[actionName] || [],
155+
req
156+
);
157+
})
158+
.then(function () {
159+
return Promise.resolve(new ControllerClass(req)[actionName]({
160+
params: params || {},
161+
body: body || {},
162+
query: query || {}
163+
}))
164+
})
137165
.then(function (result) {
138166
return options.successHandler(result);
139167
})
@@ -153,6 +181,7 @@ function controllerMappingServerSide(directory, req, options) {
153181
module.exports = {
154182
getControllerFiles,
155183
getControllerMiddleware,
184+
middlewareHandler,
156185
controllerMappingClientSide,
157186
controllerMappingServerSide
158187
};

lib/utility/http_errors.js

+7
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,10 @@ global.NotFoundError = class extends Error {
2626
this.statusCode = 404;
2727
}
2828
};
29+
30+
global.InternalServerError = class extends Error {
31+
constructor(message = 'Internal Server Error') {
32+
super(message);
33+
this.statusCode = 500;
34+
}
35+
};

tests/api.middleware.test.js

+1-15
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,16 @@ test.before(globalBeforeAll({
44
moduleOptions: {
55
prefix: '/api/v2',
66
middleware: [
7-
function (req, res, next) {
7+
function (req) {
88
req.locals = {
99
test: true
1010
};
11-
12-
next();
13-
},
14-
function (req, res, next) {
15-
if (req.query.middleware_response) {
16-
return res.status(200).json(req.locals);
17-
}
18-
19-
next();
2011
}
2112
]
2213
}
2314
}));
2415
test.after(globalAfterAll());
2516

26-
test('Test middleware for all api', async (t) => {
27-
const {data} = await api.get('/users?middleware_response=true');
28-
t.true(data.test);
29-
});
30-
3117
test('Test middleware for a controller', async (t) => {
3218
const getProducts = await api.get('/products');
3319
const getProduct = await api.get('/products/123123');

tests/fixtures/test_controller.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -93,17 +93,15 @@ TestController.ROUTES = {
9393
};
9494

9595
TestController.MIDDLEWARE = [
96-
function (req, res, next) {
96+
function (req) {
9797
if (!req.locals) req.locals = {};
9898

9999
req.locals.controller_middleware = true;
100-
next();
101100
},
102-
['allAction', function (req, res, next) {
101+
['allAction', function (req) {
103102
if (!req.locals) req.locals = {};
104103

105104
req.locals.action_middleware = true;
106-
next();
107105
}]
108106
];
109107

0 commit comments

Comments
 (0)