{"id":21283229,"url":"https://github.com/ex-machine/express-ko","last_synced_at":"2025-07-22T03:04:37.929Z","repository":{"id":101158412,"uuid":"51792241","full_name":"ex-machine/express-ko","owner":"ex-machine","description":"Brings generators, promises and async functions to Express 4.x middleware and route handlers","archived":false,"fork":false,"pushed_at":"2017-07-02T13:31:45.000Z","size":25,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-11T12:43:23.726Z","etag":null,"topics":["async-await","express","express-router","expressjs","generator-functions","javascript","middleware","promise"],"latest_commit_sha":null,"homepage":"","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/ex-machine.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-02-15T23:06:34.000Z","updated_at":"2017-07-02T13:34:26.000Z","dependencies_parsed_at":null,"dependency_job_id":"baba951f-fcdb-4d7a-9442-d57249f4fa3d","html_url":"https://github.com/ex-machine/express-ko","commit_stats":{"total_commits":25,"total_committers":2,"mean_commits":12.5,"dds":"0.19999999999999996","last_synced_commit":"e45a2959274ab52e52b96933545fa5491d4a05a2"},"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/ex-machine/express-ko","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ex-machine%2Fexpress-ko","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ex-machine%2Fexpress-ko/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ex-machine%2Fexpress-ko/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ex-machine%2Fexpress-ko/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ex-machine","download_url":"https://codeload.github.com/ex-machine/express-ko/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ex-machine%2Fexpress-ko/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266417042,"owners_count":23925300,"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","status":"online","status_checked_at":"2025-07-22T02:00:09.085Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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-await","express","express-router","expressjs","generator-functions","javascript","middleware","promise"],"created_at":"2024-11-21T11:07:31.624Z","updated_at":"2025-07-22T03:04:37.903Z","avatar_url":"https://github.com/ex-machine.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"Brings generators, promises and `async` functions to Express 4.x middleware and route handlers.\r\n\r\n[![Build Status](https://travis-ci.org/ex-machine/express-ko.svg?branch=master)](https://travis-ci.org/ex-machine/express-ko) [![Coverage Status](https://coveralls.io/repos/github/ex-machine/express-ko/badge.svg)](https://coveralls.io/github/ex-machine/express-ko)\r\n\r\n# Description\r\n\r\n`express-ko` unleashes the power of coroutines on Express middleware functions with a touch of Koa (actually, it is a portmanteau of `koa` and `co`).\r\n\r\nThe package allows to use either promise-returning functions or generator functions (they are wrapped with `co` and may `yield` promises as well) as middlewares or route callbacks.\r\n\r\n`express-ko` is nonintrusive. It doesn't hurt the behaviour of existing middlewares and route handlers but augments their functionality.\r\n\r\n## Differences with Koa\r\n\r\nAs opposed to Koa, `this` context (`ctx` parameter in Koa 2) is not provided for `ko`-ified function — particularly because Express 4.x heavily relies on function signatures, like error handlers.\r\n\r\n### Koa control flow\r\n\r\nKoa may introduce powerful (and also confusing) patterns to the flow of control, like middleware stack bouncing:\r\n\r\n```javascript\r\napp.use(function* (next) {\r\n\tthis.state.fooBar = 'foo';\r\n\t// `next` is a generator function and can be delegated\r\n\tyield* next;\r\n\tthis.body = this.state.foobar;\r\n});\r\n\r\napp.use(function* () {\r\n\tthis.state.foobar += yield Promise.resolve('bar');\r\n});\r\n```\r\n\r\n### Express control flow\r\n\r\n`express-ko` brings some syntax sugar to unsweetened callback hell, but middleware stack still works in one direction:\r\n\r\n```javascript\r\napp.use(ko(function* (req, res, next) {\r\n\tres.locals.foobar = 'foo';\r\n\t// `next` is a function and shouldn't be delegated\r\n\treturn next;\r\n}));\r\n\r\napp.use(ko(function* () {\r\n\tres.locals.foobar += yield Promise.resolve('bar');\r\n\treturn res.locals.foobar;\r\n}));\r\n```\r\n\r\n# Usage\r\n\r\n## `ko` wrapper\r\n\r\nThe wrapper created with `ko()` converts generator functions to promises via `co`. It processes resolution/rejection of a promise chain from both regular and generator functions, doing nothing on the functions that don't return promises.\r\n\r\n### Patched global router (recommended)\r\n\r\nExpress router may be patched with `ko.ify(express)` to replace all handlers supplied to router `use`, `param` and HTTP methods with wrapper functions that look for promises and generators.\r\n\r\n- `express` can be replaced with `loopback` for StrongLoop LoopBack\r\n- `ko.ify(express.Router, express.Route)` can be used to supply the constructors manually\r\n- `ko.ify(null, express.Route)` will skip `.use` and `.param` patches\r\n\r\nNo manual wrapping with `ko()` is necessary. \r\n\r\n```javascript\r\nlet express = require('express');\r\nlet ko = require('express-ko');\r\n\r\nko.ify(express);\r\n\r\nlet app = express();\r\nlet router = Router();\r\n\r\napp.use(router);\r\napp.use(function (req, res, next) { … })\r\napp.param(function* (req, res, next, val) { … });\r\nrouter.use(function (err, req, res, next) { … });\r\n```\r\n\r\n### Patched isolated router (playing safe)\r\n\r\nA new instance of `express.Router` can be required with cache-mangling packages (`rewire`, etc) and patched.\r\n\r\nThis technique is applicable to reusable router module that shouldn't affect Express applications that host it.  \r\n\r\n*Requiring entry point with `rewire('express').Router` may get cached `Router` module, it is preferable to `rewire` it directly.*\r\n\r\n```javascript\r\nlet ko = require('express-ko');\r\nlet rewire = require('rewire');\r\n\r\nlet IsolatedRouter = rewire('express/lib/router');\r\nlet IsolatedRoute = rewire('express/lib/router/route');\r\n \r\nlet Router = ko.ify(IsolatedRouter, IsolatedRoute);\r\nlet router = Router();\r\n\r\nrouter.use(function (err, req, res, next) { … });\r\n\r\nmodule.exports = router;\r\n```\r\n\r\n### Unpatched router\r\n\r\nEach callback may be wrapped with `ko()` or left intact.\r\n\r\n*`ko()` needs extra `true` argument for `param` callbacks to distinguish them from error handlers.*  \r\n\r\n```javascript\r\nlet express = require('express');\r\nlet ko = require('express-ko');\r\n\r\nlet app = express();\r\nlet router = express.Router();\r\n\r\napp.use(router);\r\napp.use(function (req, res, next) { … });\r\napp.param(ko(function* (req, res, next, id) { … }, true));\r\nrouter.use(ko(function (err, req, res, next) { … }));\r\n```\r\n\r\n# async/await \r\n\r\nCurrent implementations (TypeScript, Babel, Regenerator) fall back to generator or regular promise-returning functions, so transpiled `async` functions can be seamlessly used with `ko`.\r\n\r\n\r\n### Original way\r\n\r\n```javascript\r\napp.all('/foo', (req, res, next) =\u003e {\r\n\t….then(() =\u003e {\r\n\t\tres.send('foo');\r\n\t\tnext();\r\n\t});\r\n}); \r\n```\r\n\r\n### Suggested way (async/await)\r\n\r\n```javascript\r\napp.all('/foo', async (req, res) =\u003e {\r\n\tawait …;\r\n\treturn res.send('foo');\r\n}); \r\n```\r\n\r\n### Alternative way (generators)\r\n\r\n```javascript\r\napp.all('/foo', function* (req, res) {\r\n\tyield …;\r\n\treturn res.send('foo');\r\n}); \r\n```\r\n\r\n### Alternative way (promises)\r\n\r\n```javascript\r\napp.all('/foo', (req, res) =\u003e ….then(() =\u003e res.send('foo'))); \r\n```\r\n\r\n## Implicit `next()`\r\n\r\nA resolution with `req` or `res` chain value executes `next()` and proceeds to next handler/middleware.\r\n\r\nIt is the most suitable way of treating `res.send(…); next();` case.\r\n\r\n*Node.js HTTP methods (`.write()`, `.end()`) don't belong to Express API and aren't suitable for chaining; they return `boolean` and will cause undesirable implicit response.*\r\n\r\n### Original way\r\n\r\n```javascript\r\napp.all('/foo', (req, res, next) =\u003e {\r\n\t….then((foo) =\u003e {\r\n\t\tres.send(foo);\r\n\t\tnext();\r\n\t});\r\n}); \r\n```\r\n### Suggested way (generators)\r\n\r\n```javascript\r\napp.all('/foo', function* (req, res) {\r\n\tlet foo = yield …; \r\n\treturn res.send(foo);\r\n}); \r\n```\r\n\r\n### Alternative way (promises)\r\n\r\n```javascript\r\napp.all('/foo', (req, res) =\u003e ….then((foo) =\u003e res.send(foo))); \r\n```\r\n\r\n## Explicit `next()`\r\n\r\nA resolution with `ko.NEXT` constant or `next` (uncalled) function values executes `next()` and proceeds to next handler/middleware.\r\n\r\nIt is the most suitable way of treating the handlers where no `req` or `res` are involved.\r\n\r\n*`next()` returns `undefined`, and resolving with it has no adverse effects. This behaviour of Express isn't documented and can be changed without notice.*\r\n\r\n### Original way\r\n\r\n```javascript\r\napp.all('/foo', (req, res, next) =\u003e {\r\n\tnext();\r\n}); \r\n```\r\n\r\n### Suggested way (generators)\r\n\r\n```javascript\r\napp.all('/foo', function* () {\r\n\treturn ko.NEXT;\r\n}); \r\n```\r\n\r\n### Alternative ways (promises)\r\n\r\n```javascript\r\napp.all('/foo', () =\u003e Promise.resolve(ko.NEXT)); \r\n```\r\n\r\n```javascript\r\napp.all('/foo', (req, res, next) =\u003e Promise.resolve(next)); \r\n```\r\n\r\n## Explicit `next('route')`\r\n\r\nA resolution with `ko.NEXT_ROUTE` constant value executes `next('route')` and proceeds to next route/middleware.\r\n\r\nNo magic word 'route' (it has got odorous code smell) has to be involved in this case. \r\n\r\n\r\n### Original way\r\n\r\n```javascript\r\napp.all('/foo', (req, res, next) =\u003e {\r\n\tnext('route');\r\n}, …); \r\n```\r\n\r\n### Suggested way (generators)\r\n\r\n```javascript\r\napp.all('/foo', function* () {\r\n\treturn ko.NEXT_ROUTE;\r\n}, …); \r\n```\r\n\r\n### Alternative way (promises)\r\n\r\n```javascript\r\napp.all('/foo', () =\u003e Promise.resolve(ko.NEXT_ROUTE), …); \r\n```\r\n\r\n## Implicit `next(\u003cerror\u003e)`\r\n\r\nA resolution with `Error` object value causes promise chain rejection and executes `next(\u003cerror\u003e)`.\r\n\r\n*This behaviour is implemented to prevent the leakage of `Error` objects to response and shouldn't be intentionally used.*\r\n\r\n### Original way\r\n\r\n```javascript\r\napp.all('/foo', (req, res, next) =\u003e {\r\n\tnext(new Error);\r\n}); \r\n```\r\n\r\n### Suggested way\r\n\r\nSee *Explicit `next(\u003cerror\u003e)`*.\r\n\r\n### Alternative way (generators)\r\n\r\n```javascript\r\napp.all('/foo', function* () {\r\n\treturn new Error;\r\n}); \r\n```\r\n\r\n### Alternative way (promises)\r\n\r\n```javascript\r\napp.all('/foo', () =\u003e Promise.resolve(new Error)); \r\n```\r\n\r\n## Explicit `next(\u003cerror\u003e)`\r\n\r\nA rejection with `\u003cerror\u003e` value executes `next(\u003cerror\u003e)`.\r\n\r\n*It is preferable to throw an object and not a string, to avoid accidental usage of magic word 'route'.*\r\n\r\n### Original way\r\n\r\n```javascript\r\napp.all('/foo', (req, res, next) =\u003e {\r\n\tnext('error');\r\n}); \r\n```\r\n\r\n### Suggested way (generators)\r\n\r\n```javascript\r\napp.all('/foo', function* () {\r\n\tthrow new Error('error')\r\n}); \r\n```\r\n\r\n### Alternative ways (promises)\r\n\r\n```javascript\r\napp.all('/foo', () =\u003e ….then(() =\u003e {\r\n\tthrow new Error('error');\r\n})); \r\n```\r\n\r\n```javascript\r\napp.all('/foo', function* () {\r\n\treturn Promise.reject('error');\r\n}); \r\n```\r\n\r\n## Implicit `res.send(\u003cresponse\u003e)`\r\n\r\nA resolution with any value except `undefined` and `number` executes `res.send(\u003cresponse\u003e)`.\r\n\r\nIt is the most suitable way of treating `res.send(…)` or `res.json(…)` with no `next()` case.\r\n\r\n*`res.send(\u003cnumber\u003e)` is deprecated in favour of `res.sendStatus(\u003cnumber\u003e)`. See Express 4.x source code and API documentation on how `res.send` makes decisions on content type.*\r\n\r\n### Original way\r\n\r\n```javascript\r\napp.all('/foo', (req, res) =\u003e {\r\n\t….then((foo) =\u003e {\r\n\t\tres.send(foo);\r\n\t});\r\n}); \r\n```\r\n### Suggested way (generators)\r\n\r\n```javascript\r\napp.all('/foo', function* (req, res) {\r\n\tlet foo = yield …; \r\n\treturn foo;\r\n}); \r\n```\r\n\r\n### Alternative way (promises)\r\n\r\n```javascript\r\napp.all('/foo', (req, res) =\u003e ….then((foo) =\u003e foo)); \r\n```\r\n\r\n## Implicit `res.sendStatus(\u003cnumber\u003e)`\r\n\r\nA resolution with `number` value executes `res.sendStatus(\u003cnumber\u003e)`.\r\n\r\nIt is the most suitable way of treating `res.sendStatus(…)` with no `next()` case.\r\n\r\n### Original way\r\n\r\n```javascript\r\napp.all('/foo', (req, res) =\u003e {\r\n\t….then(() =\u003e {\r\n\t\tres.sendStatus(200);\r\n\t});\r\n}); \r\n```\r\n### Suggested way (generators)\r\n\r\n```javascript\r\napp.all('/foo', function* (req, res) {\r\n\tyield …; \r\n\treturn 200;\r\n}); \r\n```\r\n\r\n### Alternative way (promises)\r\n\r\n```javascript\r\napp.all('/foo', (req, res) =\u003e ….then(() =\u003e 200)); \r\n```\r\n\r\n# Examples\r\n\r\n`foobar` application illustrates the new syntax for asynchronous handlers and is available in [examples](examples) folder, along with `foobar-vanilla` application that features the original syntax for side-by-side comparison.\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fex-machine%2Fexpress-ko","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fex-machine%2Fexpress-ko","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fex-machine%2Fexpress-ko/lists"}