Middleware
Vercube middleware classes placed in the middleware/ directory are automatically detected and excluded from Nitro's native middleware handling. This prevents Nitro from trying to auto-register them as H3 middleware, which would cause errors since they are not standard Nitro event handlers.
How It Works
At build time the module scans the middleware/ directory (hardcoded in Nitro) and looks for classes that extend BaseMiddleware from @vercube/core. Any matching file is added to Nitro's ignore list so Nitro's own file scanner skips it.
The middleware classes are not bound to the DI container automatically - Vercube handles middleware registration differently and does not require it.
Creating a Middleware
Extend BaseMiddleware and place the file inside your middleware/ directory:
import { BaseMiddleware, UnauthorizedError } from '@vercube/core';
export class AuthMiddleware extends BaseMiddleware {
public async onRequest(request: Request): Promise<void> {
const token = request.headers.get('authorization');
if (!token) {
throw new UnauthorizedError('Missing authorization header');
}
}
}
import { BaseMiddleware } from '@vercube/core';
export class LogMiddleware extends BaseMiddleware {
public async onRequest(request: Request): Promise<void> {
console.log(`[${new Date().toISOString()}] ${request.method} ${request.url}`);
}
public async onResponse(request: Request, response: Response): Promise<void> {
console.log(`[${new Date().toISOString()}] ${response.status}`);
}
}
Applying Middleware to a Controller
Apply middleware via the @Middleware decorator on a controller class or individual method:
import { Controller, Get, Middleware } from '@vercube/core';
import { AuthMiddleware } from '../middleware/AuthMiddleware';
import { LogMiddleware } from '../middleware/LogMiddleware';
@Controller('/api/users')
@Middleware(LogMiddleware)
export class UserController {
@Get('/')
@Middleware(AuthMiddleware)
list() {
return [{ id: '1', name: 'Alice' }];
}
@Get('/public')
public() {
return [{ id: '2', name: 'Bob' }];
}
}
Global Middleware
Middleware classes in the middleware/ directory are not registered as global middleware automatically. They are only applied where you explicitly use the @Middleware decorator.
If you want a middleware to run on every request, register it in GlobalMiddlewareRegistry via a setupFile. See Global Middlewares in the core docs for the full API.
import type { App } from '@vercube/core';
import { GlobalMiddlewareRegistry } from '@vercube/core';
import { LogMiddleware } from './middleware/LogMiddleware';
export default async (app: App) => {
const registry = app.container.get(GlobalMiddlewareRegistry);
registry.registerGlobalMiddleware(LogMiddleware, { priority: 1 });
};
import { vercubeNitro } from '@vercube/nitro';
import { defineConfig } from 'nitro';
export default defineConfig({
modules: [
vercubeNitro({
setupFile: './src/container.ts',
}),
],
});
BaseMiddleware API
| Method | Arguments | Description |
|---|---|---|
onRequest | request: Request, response: Response, args: MiddlewareOptions | Called before the controller method. Throw an error to abort the request. |
onResponse | request: Request, response: Response, payload: T | Called after the controller method returns. Can modify the response. |
Both methods are optional - implement only the ones you need.
HttpError (e.g. BadRequestError, ForbiddenError). Returning a value from onRequest or onResponse is not supported - use the response argument to modify the response object instead.