route-async
A route-wrapper allowing use of async
/ await
syntax in Express
route controllers.
![NPM](https://nodei.co/npm/route-async.png?compact=true)
To Use
npm install route-async
Wrap an async
route
Assuming you have some async helper function called someAsync
, you might have a route looking a bit like this:
const asyncRoute = require('route-async')
const someAsync = require('./helpers/someAsync')
const myRoute = async (req, res) => {
const result = await someAsync(req.body)
res.json(result)
}
module.exports = asyncRoute(myRoute)
The asyncRoute
wrapper simply takes your route and wraps it, such that the async
promise is either resolved internally, or if rejected a next
function is called. The default next
is just console.error
and you can supply your own.
What about if my route wants next
Your route should not attempt to handle its own errors, but simply throw an Error
, or even better an HttpError
that gets caught by the async-route
wrapper.
This keeps your core route code much simpler.
Testing async
routes
The following example leverages mocha
, sinon
, and proxyquire
to unit test the above route by supplying a spy
in the place of the next
function.
const { expect } = require('chai')
const { spy, stub } = require('sinon')
const proxyquire = require('proxyquire')
describe('src/routes/myRoute', () => {
const mockSomeAsync = stub()
const myRoute = proxyquire('../../src/routes/myRoute', {
'./helpers/someAsync': mockSomeAsync
})
const req = { body: 'some body' }
const res = { json: stub() }
const next = spy()
const resetStubs = () => {
res.json.resetHistory()
next.resetHistory()
}
context('no errors', () => {
const result = 'some result'
before(async () => {
mockSomeAsync.resolves(result)
await myRoute(req, res, next)
})
after(resetStubs)
it('called someAsync with the right data', () => {
expect(mockSomeAsync).to.have.been.calledWith(req.body)
})
it('called res.json with the right data', () => {
expect(res.json).to.have.been.calledWith(result)
})
it("didn't call next", () => {
expect(next).not.to.have.been.called
})
})
context('has errors', () => {
const error = 'some error'
before(async () => {
mockSomeAsync.rejects(error)
await myRoute(req, res, next)
})
after(resetStubs)
it('called someAsync with the right data', () => {
expect(mockSomeAsync).to.have.been.calledWith(req.body)
})
it("didn't call res.json", () => {
expect(res.json).not.to.have.been.called
})
it('called next with the error', () => {
expect(next).to.have.been.calledWith(error)
})
})
})
Development
Branches
Branch | Status | Coverage | Audit | Comments |
---|
develop | ![CircleCI](https://circleci.com/gh/davesag/route-async/tree/develop.svg?style=svg) | ![codecov](https://codecov.io/gh/davesag/route-async/branch/develop/graph/badge.svg) | ![Vulnerabilities](https://snyk.io/test/github/davesag/route-async/develop/badge.svg) | Work in progress |
main | ![CircleCI](https://circleci.com/gh/davesag/route-async/tree/main.svg?style=svg) | ![codecov](https://codecov.io/gh/davesag/route-async/branch/main/graph/badge.svg) | ![Vulnerabilities](https://snyk.io/test/github/davesag/route-async/main/badge.svg) | Latest release |
Prerequisites
- NodeJS. I use
nvm
to manage Node versions — brew install nvm
.
Initialisation
npm install
Test it
npm test
— runs the unit testsnpm run test:unit:cov
— runs the tests with code coverage output.
Lint it
npm run lint
Contributing
Please see the contributing notes.