Koa-style compose()
Medium · Middleware
Koa runs middleware as an "onion": each async (ctx, next) => {} can do work, await next() to run the rest of the chain, then do more work on the way back. Write compose(middlewares) that returns a function (ctx) => Promise.
- Calling the composed function runs the first middleware. Its next() runs the second one, and so on. next() returns a promise that resolves when the rest of the chain is finished.
- next() in the last middleware resolves immediately.
- A middleware that does not call next() stops the chain.
- Errors (thrown or rejected) travel back up through the await next() calls, and reject the composed promise if nobody catches them.
- Calling next() twice in the same middleware must reject with Error("next() called multiple times").
The driver runMiddleware(spec) is already written. It builds middlewares from step lists: "next" awaits next(), "try-next" awaits it and logs "caught: <message>" on error, "wait" sleeps a few ms, "throw:<msg>" throws, and any other text is pushed to ctx.log. It returns the log, plus "error: <message>" if the composed promise rejected.
Next: In-Memory Todo REST API