Routing, Body Parsing & Static Files
koa-router
const Router = require('@koa/router');
const router = new Router();
router.get('/users/:id', async (ctx) => {
const user = await findUser(ctx.params.id);
ctx.body = user;
});
router.post('/users', async (ctx) => {
const user = await createUser(ctx.request.body);
ctx.status = 201;
ctx.body = user;
});
app.use(router.routes());
app.use(router.allowedMethods());Body Parsing & Static Files
const bodyParser = require('koa-bodyparser');
const serve = require('koa-static');
app.use(bodyParser()); // populates ctx.request.body
app.use(serve('./public'));Both routing and body parsing are separate middleware packages, not core features — the deliberate tradeoff of Koa's minimalist philosophy: more setup decisions upfront, no unused built-in functionality carried by default.
Short-Circuiting
app.use(async (ctx, next) => {
if (!ctx.headers.authorization) {
ctx.status = 401;
ctx.body = { error: 'Unauthorized' };
return; // not calling next() — no downstream middleware runs
}
await next();
});Koa vs. Express
Both are middleware-based Node.js frameworks built around composing small functions into a request pipeline — the core mental model transfers between them even though signatures differ ((req, res, next) vs. (ctx, next)) and Koa's minimal-core philosophy trades built-in convenience for flexibility.
Keep your own version of these notes — editable, searchable, and organised by your stack.
Start free