Frontend Development 11 min read

Understanding Middleware Design: Recursive and Chainable Implementations in Koa and Redux

This article explains the middleware design pattern in JavaScript, illustrating recursive and chainable implementations with Koa and Redux, and explores techniques such as function composition, reduceRight, parameter passing, and the role of currying and closures.

360 Tech Engineering
360 Tech Engineering
360 Tech Engineering
Understanding Middleware Design: Recursive and Chainable Implementations in Koa and Redux

Middleware is a design pattern that enables separation of concerns by allowing a series of functions to process a request sequentially. The article introduces the concept and shows a simple three‑middleware example (m1, m2, m3) that demonstrates the classic “onion” model.

Example middleware definitions:

function m1(next) {
  console.log("m1");
  next();
  console.log("v1");
}
function m2(next) {
  console.log("m2");
  next();
  console.log("v2");
}
function m3() {
  console.log("m3");
}

Two main implementation strategies are presented.

1. Recursive composition – a compose function walks the middleware array recursively, calling each next after the current middleware finishes:

const middles = [m1, m2, m3];
function compose(arr) {
  function dispatch(index) {
    if (index === arr.length) return;
    const route = arr[index];
    const next = () => dispatch(index + 1);
    return route(next);
  }
  dispatch(0);
}
compose(middles);

2. Chainable calls – middleware can be invoked directly in a nested fashion, e.g. m1(() => m2(() => m3())) , which yields the same execution order.

m1(() => m2(() => m3()));

To avoid hard‑coding the call chain, a helper createFn builds a next function for each middleware:

function createFn(middle, next) {
  return function() {
    middle(next);
  };
}
let next = () => {};
next = createFn(m3, null);
next = createFn(m2, next);
next = createFn(m1, next);
next();

The article then shows how Array.prototype.reduceRight and reduce can express the same composition more declaratively:

function compose(arr) {
  return arr.reduceRight((a, b) => () => b(a), () => {});
}
const mid = compose(middles);
mid();
function compose(arr) {
  return arr.reduce((a, b) => (...arg) => a(() => b(...arg)));
}
const mid = compose(middles);
mid();

Parameter passing between middleware is also covered. By letting a middleware call next(value) , the subsequent middleware can receive that value through a returned function:

function m1(next) {
  console.log("m1");
  next("v2");
}
function m2(next) {
  return function(action) {
    next(action);
  };
}

Finally, the article extends the pattern to Redux‑style middleware that receives an initial store object. The store is injected in a first pass, and the resulting curried functions are composed to handle actions later:

const store = { name: "redux" };
const middlesWithStore = middles.map(m => m(store));
function createFn(middle, next) {
  return action => middle(next)(action);
}
let next = () => {};
for (let i = middlesWithStore.length - 1; i >= 0; i--) {
  next = createFn(middlesWithStore[i], next);
}
next(store);

The discussion concludes by linking the whole design to functional programming concepts: currying (splitting a multi‑parameter function into a chain of single‑parameter functions) and closures (preserving the lexical environment so that later calls still have access to earlier‑captured variables). These concepts explain why Redux can inject the store once and later dispatch actions through the composed middleware chain.

In summary, middleware in Koa and Redux is built on function composition, recursion or reduction, and the powerful combination of currying and closures, enabling clean separation of concerns, flexible parameter flow, and reusable processing pipelines.

JavaScriptReduxmiddlewareKoaClosureCurrying
360 Tech Engineering
Written by

360 Tech Engineering

Official tech channel of 360, building the most professional technology aggregation platform for the brand.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.