Skip to content

Commit e9cb273

Browse files
committed
feat(bodyParsers): add body parsers middleware option (using express/body-parsers lib or custom handler). #1
1 parent ea84fd7 commit e9cb273

File tree

7 files changed

+154
-36
lines changed

7 files changed

+154
-36
lines changed

lib/module.js

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const _ = require('lodash/fp/object');
44
const DEFAULT_MODULE_OPTIONS = {
55
directory: path.resolve(__dirname, '/api'),
66
prefix: '/api',
7+
bodyParsers: 'json',
78
httpErrors: true,
89
debug: process.env.NODE_ENV !== 'production',
910
noContentStatusOnEmpty: true,

lib/server_middleware/api.js

+33-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
const express = require('express');
2-
const url = require('url');
1+
const express = require('express');
2+
const url = require('url');
3+
const expressBodyParser = require('body-parser');
4+
const { DEFAULT_PARSER_OPTIONS } = require('../utility/body_parser');
35
const { getControllerFiles, getControllerMiddleware, controllerMappingServerSide } = require('../utility/controllers');
46

57
/**
@@ -52,6 +54,32 @@ function createControllerRouter(controllerFile, options) {
5254
return router;
5355
}
5456

57+
/**
58+
* Injects body parsers to the API.
59+
*
60+
* @param options
61+
*/
62+
function injectBodyParsers(options) {
63+
const parsers = [];
64+
if (options.bodyParsers) {
65+
(Array.isArray(options.bodyParsers) ? options.bodyParsers : [options.bodyParsers]).forEach(function (parser) {
66+
if (typeof parser === 'string' && expressBodyParser.hasOwnProperty(parser)) {
67+
parsers.push(expressBodyParser[parser](DEFAULT_PARSER_OPTIONS[parser] || {}));
68+
} else if (typeof parser === 'object' && parser.adapter && expressBodyParser.hasOwnProperty(parser.adapter)) {
69+
parsers.push(expressBodyParser[parser.adapter](
70+
parser.options && Object.assign({}, DEFAULT_PARSER_OPTIONS[parser.adapter] || {}, parser.options) ||
71+
DEFAULT_PARSER_OPTIONS[parser.adapter] ||
72+
{}
73+
));
74+
} else if (typeof parser === 'function') {
75+
parsers.push(parser(options));
76+
}
77+
});
78+
}
79+
80+
return parsers;
81+
}
82+
5583
/**
5684
* Inject controllers and api routes.
5785
*
@@ -89,6 +117,9 @@ function injectAPI(options) {
89117
next();
90118
});
91119

120+
// Request body parsers
121+
router.use(...(injectBodyParsers(options)));
122+
92123
// Middleware for all API routes
93124
if (options.middleware) {
94125
router.use(...(Array.isArray(options.middleware) ? options.middleware : [options.middleware]));

lib/utility/body_parser.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const DEFAULT_PARSER_OPTIONS = {
2+
urlencoded: {
3+
extended: true // URL-encoded using qs library, which allows rich objects and arrays. (required option)
4+
}
5+
};
6+
7+
module.exports = {
8+
DEFAULT_PARSER_OPTIONS
9+
};

package-lock.json

+38-31
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
],
4747
"license": "MIT",
4848
"dependencies": {
49+
"body-parser": "^1.18.3",
4950
"config": "^1.30.0",
5051
"express": "^4.16.3",
5152
"lodash": "^4.17.10"
@@ -72,6 +73,7 @@
7273
"nuxt": "^1.4.0",
7374
"pre-commit": "^1.2.2",
7475
"prettier": "^1.12.1",
76+
"querystring": "^0.2.0",
7577
"require-extension-hooks": "^0.3.2",
7678
"require-extension-hooks-babel": "^0.1.1",
7779
"require-extension-hooks-vue": "^1.0.0",

tests/api.body.parser.test.js

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import test from 'ava';
2+
import qs from 'querystring';
3+
4+
test.before(globalBeforeAll({
5+
moduleOptions: {
6+
bodyParsers: [
7+
'json',
8+
{
9+
adapter: 'urlencoded'
10+
}
11+
]
12+
}
13+
}));
14+
test.after(globalAfterAll());
15+
16+
test('Test json body parser', async (t) => {
17+
const {data} = await api.post('/users', {
18+
first_name: 'nuxt',
19+
last_name: 'neo'
20+
});
21+
22+
t.true(data.ok);
23+
t.is(data.body.first_name, 'nuxt');
24+
t.is(data.body.last_name, 'neo');
25+
});
26+
27+
test('Test uri encoded body parser', async (t) => {
28+
const {data} = await api.post(
29+
'/users',
30+
qs.stringify({
31+
first_name: 'nuxt',
32+
last_name: 'neo'
33+
}),
34+
{
35+
headers: {
36+
'Content-Type': 'application/x-www-form-urlencoded'
37+
}
38+
}
39+
);
40+
41+
t.true(data.ok);
42+
t.is(data.body.first_name, 'nuxt');
43+
t.is(data.body.last_name, 'neo');
44+
});

yarn.lock

+27-3
Original file line numberDiff line numberDiff line change
@@ -1437,6 +1437,21 @@ body-parser@1.18.2:
14371437
raw-body "2.3.2"
14381438
type-is "~1.6.15"
14391439

1440+
body-parser@^1.18.3:
1441+
version "1.18.3"
1442+
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4"
1443+
dependencies:
1444+
bytes "3.0.0"
1445+
content-type "~1.0.4"
1446+
debug "2.6.9"
1447+
depd "~1.1.2"
1448+
http-errors "~1.6.3"
1449+
iconv-lite "0.4.23"
1450+
on-finished "~2.3.0"
1451+
qs "6.5.2"
1452+
raw-body "2.3.3"
1453+
type-is "~1.6.16"
1454+
14401455
boolbase@~1.0.0:
14411456
version "1.0.0"
14421457
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
@@ -4297,7 +4312,7 @@ http-errors@1.6.2:
42974312
setprototypeof "1.0.3"
42984313
statuses ">= 1.3.1 < 2"
42994314

4300-
http-errors@^1.2.8, http-errors@^1.6.1, http-errors@~1.6.1, http-errors@~1.6.2:
4315+
http-errors@1.6.3, http-errors@^1.2.8, http-errors@^1.6.1, http-errors@~1.6.1, http-errors@~1.6.2, http-errors@~1.6.3:
43014316
version "1.6.3"
43024317
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
43034318
dependencies:
@@ -4341,7 +4356,7 @@ iconv-lite@0.4.19:
43414356
version "0.4.19"
43424357
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b"
43434358

4344-
iconv-lite@^0.4.17, iconv-lite@^0.4.4, iconv-lite@~0.4.13:
4359+
iconv-lite@0.4.23, iconv-lite@^0.4.17, iconv-lite@^0.4.4, iconv-lite@~0.4.13:
43454360
version "0.4.23"
43464361
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
43474362
dependencies:
@@ -7258,7 +7273,7 @@ qs@6.5.1:
72587273
version "6.5.1"
72597274
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
72607275

7261-
qs@~6.5.1:
7276+
qs@6.5.2, qs@~6.5.1:
72627277
version "6.5.2"
72637278
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
72647279

@@ -7315,6 +7330,15 @@ raw-body@2.3.2:
73157330
iconv-lite "0.4.19"
73167331
unpipe "1.0.0"
73177332

7333+
raw-body@2.3.3:
7334+
version "2.3.3"
7335+
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3"
7336+
dependencies:
7337+
bytes "3.0.0"
7338+
http-errors "1.6.3"
7339+
iconv-lite "0.4.23"
7340+
unpipe "1.0.0"
7341+
73187342
rc@^1.0.1, rc@^1.1.6, rc@^1.1.7:
73197343
version "1.2.7"
73207344
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.7.tgz#8a10ca30d588d00464360372b890d06dacd02297"

0 commit comments

Comments
 (0)