Skip to content

Commit

Permalink
Merge pull request #38 from jkyberneees/improve-error-handling
Browse files Browse the repository at this point in the history
Improving error handling
  • Loading branch information
jkyberneees authored May 19, 2019
2 parents 9f0b9d5 + eb58976 commit 82298eb
Show file tree
Hide file tree
Showing 8 changed files with 310 additions and 119 deletions.
22 changes: 10 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const service = require('restana')({
- `maxParamLength`: Defines the custom length for parameters in parametric (standard, regex and multi) routes. Default value: `100`
- `defaultRoute`: Default route handler when no route match occurs. Default value: `((req, res) => res.send(404))`
- `disableResponseEvent`: If `TRUE`, there won't be `response` events triggered on the `res` object. Default value: `FALSE`
- `errorHandler`: Optional global error handler function. Default value: `(err, req, res) => res.send(err)`

```js
// accessing service configuration
Expand Down Expand Up @@ -191,22 +192,19 @@ service.start()

#### Error handling
```js
service.use((req, res, next) => {
res.on('response', e => {
if (e.code >= 400) {
if (e.data && e.data.errClass) {
console.log(e.data.errClass + ': ' + e.data.message)
} else {
console.log('error response, but not triggered by an Error instance')
}
}
})
const service = require('restana')({
errorHandler (err, req, res) {
console.log(`Something was wrong: ${err.message || err}`)
res.send(err)
}
})

return next()
service.get('/throw', (req, res) => {
throw new Error('Upps!')
})
```

Third party middlewares support:
#### Third party middlewares support:
> Almost all middlewares using the *function (req, res, next)* signature format should work, considering that no custom framework feature is used.
Examples :
Expand Down
12 changes: 12 additions & 0 deletions demos/error-handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const service = require('../index')({
errorHandler (err, req, res) {
console.log(`Unexpected error: ${err.message}`)
res.send(err)
}
})

service.get('/throw', (req, res) => {
throw new Error('Upps!')
})

service.start()
9 changes: 8 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ declare namespace restana {
next: (error?: unknown) => void
) => void | Promise<unknown>

type ErrorHandler<P extends Protocol> = (
err: Error,
req: Request<P>,
res: Response<P>,
) => void | Promise<unknown>

interface RegisterRoute<P extends Protocol> {
(
path: string,
Expand Down Expand Up @@ -104,7 +110,7 @@ declare namespace restana {
middlewares: RequestHandler<P>[]
}

interface Router {}
interface Router { }

interface Options<P extends Protocol> {
server?: Server<P>
Expand All @@ -115,6 +121,7 @@ declare namespace restana {
maxParamLength?: number
defaultRoute?: RequestHandler<P>
disableResponseEvent?: boolean
errorHandler: ErrorHandler<P>
}

interface Service<P extends Protocol> {
Expand Down
15 changes: 9 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,16 @@ module.exports = (options = {}) => {
// global middlewares holder
const middlewares = []
// routes registration shortcut factory
const addRoute = (method) => (path, ...args) => {
routeRegister(app, method, path, args)
const addRoute = (methods) => (path, ...args) => {
routeRegister(app, methods, path, args)

// supporting method chaining for routes registration
return app
}

// error handler
const errorHandler = options.errorHandler || ((err, req, res) => res.send(err))

// the "restana" service interface
const app = {
/**
Expand Down Expand Up @@ -133,13 +136,13 @@ module.exports = (options = {}) => {
...middlewares.slice(0),
{
context: {},
handler: handlerCall(handler, ctx) // -> Function
handler: handlerCall(handler, ctx, errorHandler) // -> Function
}
], req, res)()
], req, res, errorHandler)()
} else {
// directly call the route handler only
// NOTE: we do this to increase performance
handlerCall(handler, ctx)(req, res)
handlerCall(handler, ctx, errorHandler)(req, res)
}
})
} else {
Expand Down Expand Up @@ -170,7 +173,7 @@ module.exports = (options = {}) => {
router.lookup(req, res)
}
}
], req, res)()
], req, res, errorHandler)()
} else {
// directly call the request router
// NOTE: we do this to increase performance
Expand Down
9 changes: 5 additions & 4 deletions libs/middleware-chain.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
* @param {Array} middlewares
* @param {Object} req
* @param {Object} res
* @param {Function} errorHandler
*/
const next = (middlewares, req, res) => {
const next = (middlewares, req, res, errorHandler) => {
// retrieve next middleware from chain
const middleware = middlewares.shift()

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

try {
// invoke each middleware
const result = middleware.handler.call(middleware.context, req, res, next(middlewares, req, res))
const result = middleware.handler.call(middleware.context, req, res, next(middlewares, req, res, errorHandler))
if (result instanceof Promise) {
// async support
result.catch(res.send)
result.catch(err => errorHandler(err, req, res))
}
} catch (err) {
res.send(err)
errorHandler(err, req, res)
}
} else if (!res.finished) {
res.send(res.statusCode)
Expand Down
16 changes: 8 additions & 8 deletions libs/route-handler-caller.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,19 @@
*
* @param {Function} handler The request handler function
* @param {Object} ctx The request handler invokation context instance
* @param {Function} errHandler The error handler function
*/
module.exports = (handler, ctx) => (req, res) => {
module.exports = (handler, ctx, errHandler) => async (req, res) => {
try {
const result = handler.call(ctx, req, res, ctx)
// async support
if (result instanceof Promise) {
// async support
result.then(data => {
if (undefined !== data) {
return res.send(data)
}
}).catch(res.send)
const data = await result
if (undefined !== data) {
return res.send(data)
}
}
} catch (err) {
res.send(err)
errHandler(err, req, res)
}
}
Loading

0 comments on commit 82298eb

Please sign in to comment.