MasterController

Middleware

A composable pipeline that wraps every request.

Middleware are (ctx, next) functions that run in order around your routes — perfect for logging, auth, body limits, and headers. The scaffold auto-loads every file in middleware/.

A middleware file#

middleware/01-logger.js
export default async (ctx, next) => {
  const start = Date.now();
  await next();                       // run the rest of the pipeline
  const ms = Date.now() - start;
  console.log(`${ctx.type.toUpperCase()} ${ctx.request.url} — ${ms}ms`);
};

Files load alphabetically — prefix with numbers (01-, 02-) to control order. Generate one with master generate middleware auth.

Path-scoped middleware#

Export an object with register(master) to scope middleware to a path:

middleware/02-admin.js
export default {
  register: (master) => {
    master.pipeline.map('/admin/*', (admin) => {
      admin.use(async (ctx, next) => {
        if (!ctx.state.user?.isAdmin) {
          ctx.response.statusCode = 403;
          ctx.response.end('Forbidden');
          return;
        }
        await next();
      });
    });
  },
};

Registering manually#

You can also register in server.js between setupServer() and start():

javascript
master.pipeline.use(async (ctx, next) => { /* ... */ await next(); });
Ordering matters
Middleware registered before start() runs before the terminal routing middleware, so it wraps your controllers. The error handler is registered last and catches anything thrown downstream.

The context object#

  • ctx.request / ctx.response — raw Node objects.
  • ctx.type — the HTTP method.
  • ctx.state — a per-request bag shared with controllers (great for the authenticated user).