Skip to content

Sugar code layer for async middlewares and error handers, rewarding you with cleaner and more readable code.

License

Notifications You must be signed in to change notification settings

rwillians/express-rescue

Repository files navigation

JavaScript Style Guide Coverage Status CI node-current Downloads

Express Rescue

This is a dependency-free wrapper (or sugar code layer if you will) for async middlewares which makes sure all async errors are passed to your stack of error handlers, allowing you to have a cleaner and more readable code.

Note Even though this library is supposed to work on node >= 7.6, we are unable to test against node versions 7, 8 and 9 because our tooling requires at least node version 10. We'll keep the minimum requirement for this library at version node >= 7.6 so that we allow old projects to keep getting updates, but be aware that we are unable to test againt the mentioned versions.

How to use it

It's really simple:

const rescue = require('express-rescue')

/**
 * `rescue` insures thrown errors are passed to `next` callback.
 */
app.get('/:id', rescue(async (req, res, next) => {
    const user = await repository.getById(req.params.id)

    if (!user) {
      throw new UserNotFoundError
    }

    res.status(200)
       .json(user)
}))

/**
 * `rescue.from` allows you to handle a specific error which is helpful for
 * handling domain errors.
 */
app.use(rescue.from(UserNotFoundError, (err, req, res, next) => {
    res.status(404)
       .json({ error: 'these are not the droids you\'re looking for'})
})

/**
 * Your error handlers still works as expected. If an error doesn't match your
 * `rescue.from` criteria, it will find its way to the next error handler.
 */
app.use((err, req, res, next) => {
    res.status(500)
       .json({ error: 'i have a bad feeling about this'})
})

There's a helper function rescue.all([...]) in case you want to wrap several functions with rescue. With rescue.all, doing [rescue(fn1), rescue(fn2)] can be shortened to rescue.all([fn1, fn2]).

const rescue = require('express-rescue')

// Doing it like this
app.post('/products', rescue.all([
    validationFn,
    createProductFn
]))

// Is equivalent to this
app.post('/products', [
    rescue(validationFn),
    rescue(createProductFn)
])

That's all.

Hope you enjoy the async/await heaven!

Chears!

Tests

> [email protected] test
> mocha test/*.test.js --check-leaks --full-trace --use_strict --recursive

  const callable = rescue(async ([err,] req, res, next) => { })
    calls the last argument (next) with the thrown error
      ✔ All arguments are been passed to the callback
      ✔ Raises a TypeError if last argument is not a function
      ✔ callable(req, res, next) - works for routes and middlewares
      ✔ callable(err, req, res, next) - works for error handler middlewares
      ✔ callable(foo, bar, baz, foobar, foobaz, errorHandler) - should work for
        basically anything, as long as your function takes an error handler as
        the last parameter

  rescue.from(MyError, (err) => { })
    ✔ handles the error when error is instance of given constructor
    ✔ it call `next` function if error is not an instance of given constructor

  const callables = rescue.all([fn1, fn2, fn3])
    ✔ All given functions are wrapped with rescue

  8 passing (8ms)