The Basics
Middleware
Introduction
Middleware sits in the HTTP pipeline between the incoming request and your route handler. Each piece is a function with the Express shape (req, res, next) => void (or async). It can run logic, short-circuit with a response, or call next() to continue.
JCC Express MVC distinguishes two layers:
- Global middleware — wired once on the Express app for every request (framework defaults plus your HTTP kernel’s
middlewaresarray). - Route middleware — attached only to routes that reference it, using string aliases from the kernel or raw Express handlers.
For how a request walks the full stack end-to-end, see Request lifecycle (final-documentation/Architecture Concept/Request-Lifecycle.md).
HTTP kernel
Your application’s HTTP kernel lives at app/Http/kernel.ts. It is registered on the container as HttpKernel (via bootstrap/app.ts → .withKernel(Kernel)).
The class must satisfy KernelInterface:
middlewares—RequestHandler[]appended to the global Express stack after the framework’s built-in setup (body parsers, session, CORS, logging, rate limiting,HttpRequest/HttpResponse, and the per-request container binding forrequest/response/next).middlewareAliases—Record<string, RequestHandler>: short names resolved when you pass strings toRoute.middleware([...]).
Example shape:
Order in middlewares is execution order. Put cross-cutting concerns here (CSRF, method spoofing, Inertia) when they should apply broadly; use aliases for guards and throttles you attach selectively on routes.
Framework global stack (before your kernel)
The framework always registers a fixed prefix of Express middleware before your kernel's middlewares. That includes JSON/urlencoded parsing, cookies, session, flash, file uploads, CORS, Morgan, the app's rate limit config, and the request/response wrappers that attach jccSession. For req.session, req.jccSession, flash, and session(), see Session.
After those run, another middleware binds request, response, and next on the container for each request (used by request(), response(), view(), inertia(), etc.).
The numbered list of default middleware is documented in Request lifecycle; you normally do not edit that class from an app—customize CORS and rate limiting through app/Config where applicable, and extend behavior via the kernel or route middleware.
Route middleware
Attaching middleware
Use Route.middleware(...) immediately before the verb you register. The argument may be:
- A string — must exist on
kernel.middlewareAliases. - An array — mix strings (resolved to aliases) and raw
RequestHandlerfunctions. - A single
RequestHandler— used as-is.
If an alias string is missing, RouteBuilder throws (for example auth middleware not found in alias middleware).
Groups
Inside Route.prefix(...).group(...) or Route.group(...), call Route.middleware([...]) before defining routes. Nested groups flatten parent group middleware first, then child group middleware, then any middleware chained right before Route.get / post / etc.
When the route is registered on Express, global stack → matched route → route middleware (in that order) → handler.
Writing custom middleware
A middleware is a RequestHandler: (req, res, next) => void. Call next() when the request should continue; pass next(err) to delegate to the error handler. For async work, either use async / await and catch errors, or wrap with the framework’s asyncHandler if you need consistent error propagation.
Register reusable app middleware as functions or small modules, then either:
- Add them to
kernel.middlewareAliasesunder a name and reference that name in routes, or - Pass the function directly into
Route.middleware(myHandler)or an array alongside strings.
Example alias:
Built-in and framework exports
Common pieces you import rather than reimplement:
csrf()/methodSpoofing()fromjcc-express-mvc/Core— web forms and unsafe verbs. Full CSRF usage (@csrf, AJAX headers, options) is in CSRF protection.auth,guest,apiAuth— fromjcc-express-mvc(session/JWT-style behavior depends on your auth setup).loginRateLimit/registerRateLimit— aliased in the sample kernel asloginThrottle/registerThrottle.inertia(...)— root view and SSR options for Inertia responses.
Tune global behavior in kernel.middlewares; tune per-route access with aliases on specific routes or groups.
Inspecting middleware on routes
List registered routes and their middleware:
Middleware runs before your controller or closure. Keep handlers small, call next() when appropriate, and register aliases for anything you reuse across many routes.