Run a middleware chain with next()
A middleware chain is the most useful closure pattern there is. Each function receives a shared context and a next callback; whatever it does before calling next() happens on the way in, and whatever it does after happens on the way out, once everything downstream has finished. Not calling next() short-circuits the rest of the chain — which is how an auth middleware rejects a request.
Implement createPipeline(). It returns an object with use(middleware), which registers a middleware and returns the pipeline itself so registrations can be chained, and run(context), which executes the middlewares synchronously in registration order and returns the same context object it was given. Each middleware is called as middleware(context, next). Calling next() runs the rest of the chain and returns once the rest of the chain has finished, so code after next() runs in reverse registration order. A middleware that never calls next() prevents every later middleware from running. Calling next() more than once in the same middleware throws new Error("next() called multiple times"). A pipeline with no middlewares simply returns the context.
Returns
{ use(middleware): this; run(context): any } — A pipeline whose use chains registrations and whose run dispatches the chain over a context.
Examples
const pipeline = createPipeline()
.use((ctx, next) => { ctx.steps.push("a-in"); next(); ctx.steps.push("a-out"); })
.use((ctx, next) => { ctx.steps.push("b-in"); next(); ctx.steps.push("b-out"); });
pipeline.run({ steps: [] });
// { steps: ["a-in", "b-in", "b-out", "a-out"] } — onion orderCode before next() runs on the way in; code after runs on the way out.
const pipeline = createPipeline()
.use((ctx, next) => { if (!ctx.user) return; next(); }) // guard
.use((ctx, next) => { ctx.handled = true; next(); });
pipeline.run({}); // { } — guard skipped the handler
pipeline.run({ user: 1 }); // { user: 1, handled: true }What it has to do
useregisters a middleware and returns the pipeline so calls chain.runexecutes middlewares in registration order and returns the context it was given.- Code after
next()runs on the way back out, in reverse registration order. - A middleware that does not call
next()stops the rest of the chain. - Calling
next()twice throwsError("next() called multiple times").
Notes
- Recursion, not a loop: a
dispatch(index)function that gives each middleware anextclosing overindex + 1. The call stack is the "onion". - Track the highest-dispatched index to detect a second
next()— a duplicate dispatch would otherwise silently re-run the tail of the chain.
Stuck? The javascript course covers everything this challenge needs.
- 1.runs middlewares in order and returns the context
- 2.code after next() runs on the way back out
- 3.skipping next() short-circuits the chain
- 4.an empty pipeline returns the context untouched
- 5.calling next() twice throws
These assertions run in your browser the moment you hit Run. Pass all of them to claim the XP.
Discussion
Sign in to postNo comments yet. Be the first to say something.