Skip to content

Commit 4c882eb

Browse files
authored
Merge pull request #8 from Yoctol/pass-error-message
always pass error message
2 parents 95139d0 + 8205926 commit 4c882eb

File tree

4 files changed

+119
-35
lines changed

4 files changed

+119
-35
lines changed

__tests__/index.spec.js

Lines changed: 51 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
/* eslint-disable no-shadow */
22
import compose from 'koa-compose';
33
import validate, { object, string } from 'koa-context-validator';
4+
import createError from 'http-errors';
45

56
import finalHandler from '../';
67

78
const middleware = finalHandler();
89

9-
const createContext = ({ status }) => ({
10+
const createContext = ({ status } = {}) => ({
1011
request: {
1112
method: 'GET',
1213
url: '/private',
@@ -36,6 +37,7 @@ const createContext = ({ status }) => ({
3637
const nodeEnv = process.env.NODE_ENV;
3738

3839
beforeEach(() => {
40+
console.error = jest.fn();
3941
jest.resetModules();
4042
});
4143

@@ -74,9 +76,8 @@ describe('finalHandler', () => {
7476

7577
it('call error if error happens', async () => {
7678
const error = new Error('my error');
77-
const ctx = createContext({ status: 500 });
79+
const ctx = createContext();
7880
const next = jest.fn(() => Promise.reject(error));
79-
console.error = jest.fn();
8081

8182
await middleware(ctx, next);
8283

@@ -91,50 +92,73 @@ describe('finalHandler', () => {
9192
const middleware = finalHandler();
9293

9394
const error = new Error('my error');
94-
const ctx = createContext({ status: 500 });
95+
const ctx = createContext();
9596
const next = jest.fn(() => Promise.reject(error));
96-
console.error = jest.fn();
9797

9898
await middleware(ctx, next);
9999

100-
expect(ctx.response.body).toEqual({ error });
100+
expect(ctx.response.body).toEqual({
101+
error,
102+
});
101103
});
102104

103-
it('will not get error on response.body when NODE_ENV is `production`', async () => {
105+
it('put status message to error message', async () => {
106+
process.env.NODE_ENV = 'development';
107+
108+
const finalHandler = require('../');
109+
const middleware = finalHandler();
110+
111+
const error = createError(401);
112+
const ctx = createContext();
113+
const next = jest.fn(() => Promise.reject(error));
114+
115+
await middleware(ctx, next);
116+
117+
expect(ctx.response.body).toEqual({
118+
error: {
119+
message: 'Unauthorized',
120+
},
121+
});
122+
});
123+
124+
it('will not get error details on response.body when NODE_ENV is `production`', async () => {
104125
process.env.NODE_ENV = 'production';
105126

106127
const finalHandler = require('../');
107128
const middleware = finalHandler();
108129

109130
const error = new Error('my error');
110-
const ctx = createContext({ status: 500 });
131+
const ctx = createContext();
111132
const next = jest.fn(() => Promise.reject(error));
112-
console.error = jest.fn();
113133

114134
await middleware(ctx, next);
115135

116-
expect(ctx.response.body).toBeUndefined();
136+
expect(ctx.response.body).toEqual({
137+
error: {
138+
message: 'Internal Server Error',
139+
},
140+
});
117141
});
118-
});
119142

120-
it('should support Joi errors', async () => {
121-
const composed = compose([
122-
middleware,
123-
validate({
124-
body: object().keys({
125-
username: string().required(),
143+
it('should support Joi errors', async () => {
144+
const composed = compose([
145+
middleware,
146+
validate({
147+
body: object().keys({
148+
username: string().required(),
149+
}),
126150
}),
127-
}),
128-
]);
151+
]);
129152

130-
const ctx = createContext({});
131-
const next = jest.fn(() => Promise.resolve());
153+
const ctx = createContext();
154+
const next = jest.fn(() => Promise.resolve());
132155

133-
await composed(ctx, next);
156+
await composed(ctx, next);
134157

135-
expect(ctx.response.status).toEqual(400);
136-
expect(ctx.response.body).toHaveProperty(
137-
'error.message',
138-
'"username" is required'
139-
);
158+
expect(ctx.response.status).toEqual(400);
159+
expect(ctx.response.body).toHaveProperty(
160+
'error.message',
161+
'"username" is required'
162+
);
163+
});
140164
});

index.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const HTTP_STATUS = require('http-status');
2+
13
const { NODE_ENV } = process.env;
24

35
const finalHandler = () => async (ctx, next) => {
@@ -25,6 +27,15 @@ const finalHandler = () => async (ctx, next) => {
2527
ctx.response.body = { error };
2628
}
2729
}
30+
31+
if (!ctx.response.body) {
32+
ctx.response.body = {
33+
error: {
34+
message: HTTP_STATUS[ctx.response.status],
35+
},
36+
};
37+
}
38+
2839
ctx.app.emit('error', error, ctx);
2940
}
3041
};

package.json

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
"engines": {
1212
"node": ">=7.6"
1313
},
14-
"files": ["index.js"],
14+
"files": [
15+
"index.js"
16+
],
1517
"scripts": {
1618
"lint": "eslint .",
1719
"lint:fix": "npm run lint -- --fix",
@@ -31,6 +33,7 @@
3133
"eslint-config-yoctol-base": "^0.15.1",
3234
"eslint-plugin-import": "^2.11.0",
3335
"eslint-plugin-prettier": "^2.6.0",
36+
"http-errors": "^1.6.3",
3437
"husky": "^0.14.3",
3538
"jest": "^22.4.3",
3639
"koa-compose": "^4.0.0",
@@ -39,20 +42,41 @@
3942
"prettier": "^1.12.1",
4043
"prettier-package-json": "^1.6.0"
4144
},
42-
"keywords": ["final-handler", "handler", "koa", "middleware"],
45+
"keywords": [
46+
"final-handler",
47+
"handler",
48+
"koa",
49+
"middleware"
50+
],
4351
"jest": {
44-
"setupFiles": ["./test/configure-env.js"],
52+
"setupFiles": [
53+
"./test/configure-env.js"
54+
],
4555
"testEnvironment": "node",
46-
"testPathIgnorePatterns": ["node_modules/"]
56+
"testPathIgnorePatterns": [
57+
"node_modules/"
58+
]
4759
},
4860
"lint-staged": {
49-
"*.{json,md}": ["prettier --write", "git add"],
50-
"*.js": ["eslint --fix", "git add"],
61+
"*.{json,md}": [
62+
"prettier --write",
63+
"git add"
64+
],
65+
"*.js": [
66+
"eslint --fix",
67+
"git add"
68+
],
5169
"package.json": [
5270
"prettier-package-json --write",
5371
"prettier --write",
5472
"git add"
5573
],
56-
".babelrc": ["prettier --parser json --write", "git add"]
74+
".babelrc": [
75+
"prettier --parser json --write",
76+
"git add"
77+
]
78+
},
79+
"dependencies": {
80+
"http-status": "^1.2.0"
5781
}
5882
}

yarn.lock

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,10 @@ delegates@^1.0.0:
13371337
version "1.0.0"
13381338
resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
13391339

1340+
depd@~1.1.2:
1341+
version "1.1.2"
1342+
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
1343+
13401344
detect-indent@^4.0.0:
13411345
version "4.0.0"
13421346
resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208"
@@ -2060,6 +2064,15 @@ html-encoding-sniffer@^1.0.2:
20602064
dependencies:
20612065
whatwg-encoding "^1.0.1"
20622066

2067+
http-errors@^1.6.3:
2068+
version "1.6.3"
2069+
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
2070+
dependencies:
2071+
depd "~1.1.2"
2072+
inherits "2.0.3"
2073+
setprototypeof "1.1.0"
2074+
statuses ">= 1.4.0 < 2"
2075+
20632076
http-signature@~1.2.0:
20642077
version "1.2.0"
20652078
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
@@ -2068,6 +2081,10 @@ http-signature@~1.2.0:
20682081
jsprim "^1.2.2"
20692082
sshpk "^1.7.0"
20702083

2084+
http-status@^1.2.0:
2085+
version "1.2.0"
2086+
resolved "https://registry.yarnpkg.com/http-status/-/http-status-1.2.0.tgz#05f2a54c94f94d32d877b3a31ae08479772ba9f1"
2087+
20712088
husky@^0.14.3:
20722089
version "0.14.3"
20732090
resolved "https://registry.yarnpkg.com/husky/-/husky-0.14.3.tgz#c69ed74e2d2779769a17ba8399b54ce0b63c12c3"
@@ -2130,7 +2147,7 @@ inflight@^1.0.4:
21302147
once "^1.3.0"
21312148
wrappy "1"
21322149

2133-
inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3:
2150+
inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3:
21342151
version "2.0.3"
21352152
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
21362153

@@ -4042,6 +4059,10 @@ set-value@^2.0.0:
40424059
is-plain-object "^2.0.3"
40434060
split-string "^3.0.1"
40444061

4062+
4063+
version "1.1.0"
4064+
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
4065+
40454066
shebang-command@^1.2.0:
40464067
version "1.2.0"
40474068
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
@@ -4217,6 +4238,10 @@ static-extend@^0.1.1:
42174238
define-property "^0.2.5"
42184239
object-copy "^0.1.0"
42194240

4241+
"statuses@>= 1.4.0 < 2":
4242+
version "1.5.0"
4243+
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
4244+
42204245
stealthy-require@^1.1.0:
42214246
version "1.1.1"
42224247
resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b"

0 commit comments

Comments
 (0)