-
Notifications
You must be signed in to change notification settings - Fork 0
Interceptors
An interceptor wraps a controller-method call (onion / around advice): it runs code before the method, awaits the downstream result, and may transform or replace it before it flows into response handling. Unlike a guard, an interceptor does not make a yes/no decision — it shapes what crosses a handler's boundary.
Interceptors live in nextrush/class and apply only to class-based controller routes. They
are opt-in and non-breaking: a route with no @UseInterceptor behaves exactly as before —
the method result flows straight into response handling.
An interceptor is a class that implements the Interceptor interface:
import { Service } from '@nextrush/di';
import type { Interceptor, Context } from 'nextrush/class';
@Service()
class WrapInterceptor implements Interceptor {
constructor(private readonly logger: Logger) {}
async intercept(ctx: Context, next: () => Promise<unknown>): Promise<unknown> {
const start = performance.now();
try {
const result = await next(); // the downstream result (ultimately the handler's return)
this.logger.info(`${ctx.method} ${ctx.path}`, performance.now() - start);
return { data: result, timestamp: Date.now() }; // transform what proceeds to response
} catch (err) {
this.logger.error('handler failed', err);
throw err; // rethrow so exception filters / error middleware handle it
}
}
}
// Class-level wraps every route; method-level wraps one route.
@Controller('/orders')
class OrdersController {
@UseInterceptor(WrapInterceptor)
@Get()
list() {
return loadOrders();
}
}import { createApp } from 'nextrush';
import { Module, registerModule } from 'nextrush/class';
// Wire the controller and interceptor through an AppModule:
@Module({
controllers: [OrdersController],
providers: [Logger, WrapInterceptor],
})
class OrdersModule {}
@Module({ imports: [OrdersModule] })
class AppModule {}
const app = createApp();
await registerModule(app, AppModule);-
intercept(ctx, next)receives the same requestContextthe handler gets (@nextrush/types) — readmethod,path,params,query,headers,body,state,get(name). -
next()invokes the rest of the chain to the inside and resolves to the handler's return value. Await it to observe the result. - Whatever
interceptreturns becomes the result that flows into response handling. Returnnext()'s value unchanged to pass through, or a different value to transform. - Interceptor classes are resolved from the DI container at request time, so they may inject services (loggers, metrics, mappers).
Class-level interceptors are the outermost layers; method-level interceptors are inner,
closest to the handler. The innermost next() invokes the actual method.
@UseInterceptor(LoggingInterceptor) // A [ outer ]
@Controller('/orders')
class OrdersController {
@UseInterceptor(TimingInterceptor) // B [ inner ]
@Get()
list() {
return getOrders();
}
}
// Execution: A.intercept → B.intercept → handler.list → B unwinds → A unwinds.Both class and method interceptors are collected per route (class first, then method), and the
chain is folded so the first entry runs first and unwinds last. Within a single
@UseInterceptor(A, B), A is outer to B.
-
Response shaping / envelope wrapping —
interceptreturns{ data, timestamp }. - Timing, logging, and metrics around the handler.
-
Caching — short-circuit
next()and return a cached value. -
Cross-cutting error mapping —
try/catcharoundnext(). -
Telemetry — tag
ctx.stateand read it in nested interceptors.
- Access checks — that is a guard (interceptors run at the method, too late to gate).
- Global side effects for every request regardless of route — that is middleware.
- Yes/no decisions before the handler — again, a guard.
An error the interceptor does not handle propagates out — exception filters, which wrap the whole handler, can still catch it.
- Guards — yes/no gate that runs before the method; interceptors wrap at the method
- Exception Filters — catch an error an interceptor or handler rethrows
-
Controllers & Decorators — where
@UseInterceptoris applied - Dependency Injection — how an interceptor gets its injected services
- Interceptors reference: https://0xtanzim.github.io/nextRush/docs/concepts/interceptors
NextRush · MIT License · Docs · Issues