Angelos Orfanakos

Passing data between middleware in Koa.js

I recently started playing with Koa.js, a minimal Node.js framework by the team behind Express.js.

From the official documentation:

Philosophically, Koa aims to “fix and replace node”, whereas Express “augments node”. Koa uses promises and async functions to rid apps of callback hell and simplify error handling. It exposes its own ctx.request and ctx.response objects instead of node’s req and res objects.

Express, on the other hand, augments node’s req and res objects with additional properties and methods and includes many other “framework” features, such as routing and templating, which Koa does not.

Thus, Koa can be viewed as an abstraction of node.js’s http modules, where as Express is an application framework for node.js.

One thing I initially struggled with is how data is passed between middleware. Once I figured it out, I came up with the following example to demonstrate it:

const Koa = require('koa');

const app = new Koa();

// First middleware (1)
app.use(async (ctx, next) => {
  console.log(1, ctx.state); // 1
  ctx.state.name = 'John'; // 2  console.log(1, ctx.state); // 3

  const age = await next(); // 4 (await), 9 (assignment)
  console.log(1, ctx.state); // 10
  ctx.body = `${ctx.state.name} ${ctx.state.surname} is ${age} years old`; // 11
});

// Second middleware (2)
app.use(async (ctx) => {
  console.log(2, ctx.state); // 5
  ctx.state.surname = 'Doe'; // 6  console.log(2, ctx.state); // 7

  return 33; // 8});

app.listen(3000);

Things to note:

  • Numbers in comments indicate execution order
  • Middleware execution happens in a “stack order”
  • ctx.state can be used to share state between middleware
  • If a middleware returns a value, that value is returned to the parent middleware that awaited it

Visit http://localhost:3000 and you should see:

John Doe is 33 years old

With the following logs:

1 {}
1 { name: 'John' }
2 { name: 'John' }
2 { name: 'John', surname: 'Doe' }
1 { name: 'John', surname: 'Doe' }

Enjoy!