Skip to content

Commit 82298eb

Browse files
authored
Merge pull request #38 from jkyberneees/improve-error-handling
Improving error handling
2 parents 9f0b9d5 + eb58976 commit 82298eb

File tree

8 files changed

+310
-119
lines changed

8 files changed

+310
-119
lines changed

README.md

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const service = require('restana')({
3939
- `maxParamLength`: Defines the custom length for parameters in parametric (standard, regex and multi) routes. Default value: `100`
4040
- `defaultRoute`: Default route handler when no route match occurs. Default value: `((req, res) => res.send(404))`
4141
- `disableResponseEvent`: If `TRUE`, there won't be `response` events triggered on the `res` object. Default value: `FALSE`
42+
- `errorHandler`: Optional global error handler function. Default value: `(err, req, res) => res.send(err)`
4243

4344
```js
4445
// accessing service configuration
@@ -191,22 +192,19 @@ service.start()
191192

192193
#### Error handling
193194
```js
194-
service.use((req, res, next) => {
195-
res.on('response', e => {
196-
if (e.code >= 400) {
197-
if (e.data && e.data.errClass) {
198-
console.log(e.data.errClass + ': ' + e.data.message)
199-
} else {
200-
console.log('error response, but not triggered by an Error instance')
201-
}
202-
}
203-
})
195+
const service = require('restana')({
196+
errorHandler (err, req, res) {
197+
console.log(`Something was wrong: ${err.message || err}`)
198+
res.send(err)
199+
}
200+
})
204201

205-
return next()
202+
service.get('/throw', (req, res) => {
203+
throw new Error('Upps!')
206204
})
207205
```
208206

209-
Third party middlewares support:
207+
#### Third party middlewares support:
210208
> Almost all middlewares using the *function (req, res, next)* signature format should work, considering that no custom framework feature is used.
211209
212210
Examples :

demos/error-handler.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
const service = require('../index')({
2+
errorHandler (err, req, res) {
3+
console.log(`Unexpected error: ${err.message}`)
4+
res.send(err)
5+
}
6+
})
7+
8+
service.get('/throw', (req, res) => {
9+
throw new Error('Upps!')
10+
})
11+
12+
service.start()

index.d.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ declare namespace restana {
5757
next: (error?: unknown) => void
5858
) => void | Promise<unknown>
5959

60+
type ErrorHandler<P extends Protocol> = (
61+
err: Error,
62+
req: Request<P>,
63+
res: Response<P>,
64+
) => void | Promise<unknown>
65+
6066
interface RegisterRoute<P extends Protocol> {
6167
(
6268
path: string,
@@ -104,7 +110,7 @@ declare namespace restana {
104110
middlewares: RequestHandler<P>[]
105111
}
106112

107-
interface Router {}
113+
interface Router { }
108114

109115
interface Options<P extends Protocol> {
110116
server?: Server<P>
@@ -115,6 +121,7 @@ declare namespace restana {
115121
maxParamLength?: number
116122
defaultRoute?: RequestHandler<P>
117123
disableResponseEvent?: boolean
124+
errorHandler: ErrorHandler<P>
118125
}
119126

120127
interface Service<P extends Protocol> {

index.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,16 @@ module.exports = (options = {}) => {
6060
// global middlewares holder
6161
const middlewares = []
6262
// routes registration shortcut factory
63-
const addRoute = (method) => (path, ...args) => {
64-
routeRegister(app, method, path, args)
63+
const addRoute = (methods) => (path, ...args) => {
64+
routeRegister(app, methods, path, args)
6565

6666
// supporting method chaining for routes registration
6767
return app
6868
}
6969

70+
// error handler
71+
const errorHandler = options.errorHandler || ((err, req, res) => res.send(err))
72+
7073
// the "restana" service interface
7174
const app = {
7275
/**
@@ -133,13 +136,13 @@ module.exports = (options = {}) => {
133136
...middlewares.slice(0),
134137
{
135138
context: {},
136-
handler: handlerCall(handler, ctx) // -> Function
139+
handler: handlerCall(handler, ctx, errorHandler) // -> Function
137140
}
138-
], req, res)()
141+
], req, res, errorHandler)()
139142
} else {
140143
// directly call the route handler only
141144
// NOTE: we do this to increase performance
142-
handlerCall(handler, ctx)(req, res)
145+
handlerCall(handler, ctx, errorHandler)(req, res)
143146
}
144147
})
145148
} else {
@@ -170,7 +173,7 @@ module.exports = (options = {}) => {
170173
router.lookup(req, res)
171174
}
172175
}
173-
], req, res)()
176+
], req, res, errorHandler)()
174177
} else {
175178
// directly call the request router
176179
// NOTE: we do this to increase performance

libs/middleware-chain.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
* @param {Array} middlewares
55
* @param {Object} req
66
* @param {Object} res
7+
* @param {Function} errorHandler
78
*/
8-
const next = (middlewares, req, res) => {
9+
const next = (middlewares, req, res, errorHandler) => {
910
// retrieve next middleware from chain
1011
const middleware = middlewares.shift()
1112

@@ -16,13 +17,13 @@ const next = (middlewares, req, res) => {
1617

1718
try {
1819
// invoke each middleware
19-
const result = middleware.handler.call(middleware.context, req, res, next(middlewares, req, res))
20+
const result = middleware.handler.call(middleware.context, req, res, next(middlewares, req, res, errorHandler))
2021
if (result instanceof Promise) {
2122
// async support
22-
result.catch(res.send)
23+
result.catch(err => errorHandler(err, req, res))
2324
}
2425
} catch (err) {
25-
res.send(err)
26+
errorHandler(err, req, res)
2627
}
2728
} else if (!res.finished) {
2829
res.send(res.statusCode)

libs/route-handler-caller.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,19 @@
33
*
44
* @param {Function} handler The request handler function
55
* @param {Object} ctx The request handler invokation context instance
6+
* @param {Function} errHandler The error handler function
67
*/
7-
module.exports = (handler, ctx) => (req, res) => {
8+
module.exports = (handler, ctx, errHandler) => async (req, res) => {
89
try {
910
const result = handler.call(ctx, req, res, ctx)
11+
// async support
1012
if (result instanceof Promise) {
11-
// async support
12-
result.then(data => {
13-
if (undefined !== data) {
14-
return res.send(data)
15-
}
16-
}).catch(res.send)
13+
const data = await result
14+
if (undefined !== data) {
15+
return res.send(data)
16+
}
1717
}
1818
} catch (err) {
19-
res.send(err)
19+
errHandler(err, req, res)
2020
}
2121
}

0 commit comments

Comments
 (0)