{"id":21283228,"url":"https://github.com/davesag/route-async","last_synced_at":"2025-07-11T11:30:43.308Z","repository":{"id":32830329,"uuid":"143822927","full_name":"davesag/route-async","owner":"davesag","description":"A route wrapper allowing use of async / await syntax in Express route controllers","archived":false,"fork":false,"pushed_at":"2024-04-23T05:57:33.000Z","size":1850,"stargazers_count":8,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"develop","last_synced_at":"2024-05-02T00:12:31.865Z","etag":null,"topics":["async","async-await","es6-javascript","expressjs"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/davesag.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null},"funding":{"github":["davesag"]}},"created_at":"2018-08-07T05:13:00.000Z","updated_at":"2024-04-23T05:57:37.000Z","dependencies_parsed_at":"2024-02-14T08:22:58.172Z","dependency_job_id":"9423fafe-6b82-4dc8-84be-5266f47980be","html_url":"https://github.com/davesag/route-async","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davesag%2Froute-async","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davesag%2Froute-async/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davesag%2Froute-async/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/davesag%2Froute-async/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/davesag","download_url":"https://codeload.github.com/davesag/route-async/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225476245,"owners_count":17480222,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async","async-await","es6-javascript","expressjs"],"created_at":"2024-11-21T11:07:31.255Z","updated_at":"2024-11-21T11:07:31.959Z","avatar_url":"https://github.com/davesag.png","language":"JavaScript","funding_links":["https://github.com/sponsors/davesag"],"categories":[],"sub_categories":[],"readme":"# route-async\n\nA route-wrapper allowing use of `async` / `await` syntax in [`Express`](https://expressjs.com) route controllers.\n\n[![NPM](https://nodei.co/npm/route-async.png?compact=true)](https://nodei.co/npm/route-async/)\n\n## To Use\n\n```sh\nnpm install route-async\n```\n\n## Wrap an `async` route\n\nAssuming you have some async helper function called `someAsync`, you might have a route looking a bit like this:\n\n```js\nconst asyncRoute = require('route-async')\nconst someAsync = require('./helpers/someAsync')\n\nconst myRoute = async (req, res) =\u003e {\n  const result = await someAsync(req.body)\n  res.json(result)\n}\n\nmodule.exports = asyncRoute(myRoute)\n```\n\nThe `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.\n\n### What about if my route wants `next`\n\nYour route should not attempt to handle its own errors, but simply throw an `Error`, or even better an [`HttpError`](https://github.com/jshttp/http-errors) that gets caught by the `async-route` wrapper.\n\nThis keeps your core route code much simpler.\n\n## Testing `async` routes\n\nThe following example leverages [`mocha`](https://mochajs.org), [`sinon`](https://sinonjs.org), and [`proxyquire`](https://github.com/thlorenz/proxyquire) to unit test the above route by supplying a `spy` in the place of the `next` function.\n\n```js\nconst { expect } = require('chai')\nconst { spy, stub } = require('sinon')\nconst proxyquire = require('proxyquire')\n\ndescribe('src/routes/myRoute', () =\u003e {\n  const mockSomeAsync = stub()\n\n  const myRoute = proxyquire('../../src/routes/myRoute', {\n    './helpers/someAsync': mockSomeAsync\n  })\n\n  const req = { body: 'some body' }\n  const res = { json: stub() }\n  const next = spy()\n\n  const resetStubs = () =\u003e {\n    res.json.resetHistory()\n    next.resetHistory()\n  }\n\n  context('no errors', () =\u003e {\n    const result = 'some result'\n\n    before(async () =\u003e {\n      mockSomeAsync.resolves(result)\n      await myRoute(req, res, next)\n    })\n\n    after(resetStubs)\n\n    it('called someAsync with the right data', () =\u003e {\n      expect(mockSomeAsync).to.have.been.calledWith(req.body)\n    })\n\n    it('called res.json with the right data', () =\u003e {\n      expect(res.json).to.have.been.calledWith(result)\n    })\n\n    it(\"didn't call next\", () =\u003e {\n      expect(next).not.to.have.been.called\n    })\n  })\n\n  context('has errors', () =\u003e {\n    const error = 'some error'\n\n    before(async () =\u003e {\n      mockSomeAsync.rejects(error)\n      await myRoute(req, res, next)\n    })\n\n    after(resetStubs)\n\n    it('called someAsync with the right data', () =\u003e {\n      expect(mockSomeAsync).to.have.been.calledWith(req.body)\n    })\n\n    it(\"didn't call res.json\", () =\u003e {\n      expect(res.json).not.to.have.been.called\n    })\n\n    it('called next with the error', () =\u003e {\n      expect(next).to.have.been.calledWith(error)\n    })\n  })\n})\n```\n\n## Development\n\n### Branches\n\n\u003c!-- prettier-ignore --\u003e\n| Branch   | Status  | Coverage  | Audit | Comments  |\n| -------- | ------- | --------- | ----- | --------- |\n| `develop` | [![CircleCI](https://circleci.com/gh/davesag/route-async/tree/develop.svg?style=svg)](https://circleci.com/gh/davesag/route-async/tree/develop) | [![codecov](https://codecov.io/gh/davesag/route-async/branch/develop/graph/badge.svg)](https://codecov.io/gh/davesag/route-async) | [![Vulnerabilities](https://snyk.io/test/github/davesag/route-async/develop/badge.svg)](https://snyk.io/test/github/davesag/route-async/develop) | Work in progress |\n| `main` | [![CircleCI](https://circleci.com/gh/davesag/route-async/tree/main.svg?style=svg)](https://circleci.com/gh/davesag/route-async/tree/main) | [![codecov](https://codecov.io/gh/davesag/route-async/branch/main/graph/badge.svg)](https://codecov.io/gh/davesag/route-async) | [![Vulnerabilities](https://snyk.io/test/github/davesag/route-async/main/badge.svg)](https://snyk.io/test/github/davesag/route-async/main) | Latest release |\n\n### Prerequisites\n\n- [NodeJS](htps://nodejs.org). I use [`nvm`](https://github.com/creationix/nvm) to manage Node versions — `brew install nvm`.\n\n### Initialisation\n\n```sh\nnpm install\n```\n\n### Test it\n\n- `npm test` — runs the unit tests\n- `npm run test:unit:cov` — runs the tests with code coverage output.\n\n### Lint it\n\n```sh\nnpm run lint\n```\n\n## Contributing\n\nPlease see the [contributing notes](CONTRIBUTING.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavesag%2Froute-async","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdavesag%2Froute-async","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdavesag%2Froute-async/lists"}