A request wrapper runs code around the rest of the pipeline. It does its setup, calls
next() to run middleware, guards, interceptors, and the endpoint, and then does its teardown with the finished
Response available. Use it when something has to span the whole request, such as a Zone
value, a database transaction, or a try/finally cleanup.
For the common case of one instance per request, request-scoped dependencies already give every request its own DI scope. You don't need a wrapper for that.
Example#
import 'package:revali_router/revali_router.dart';
class ServerTiming implements LifecycleComponent {
const ServerTiming();
WrapperResult wrap(NextResponse next) async {
final watch = Stopwatch()..start();
try {
return await next();
} finally {
print('request took ${watch.elapsedMilliseconds}ms');
}
}
}
Apply it with @ServerTiming() on the app, a controller, or an endpoint. Every request it covers is timed, including requests that a guard blocks or that throw.
Rules#
-
The method must return
WrapperResult(an alias forFuture<Response>) and take aNextResponseparameter. Without theNextResponseparameter, the method is not treated as a wrapper. -
Call
next()exactly once and return itsResponse. To short-circuit, return aResponsewithout callingnext(). -
Other parameters bind like any other component method, for example
Request,Data, orDI. - Several wrappers nest: the first one registered is the outermost. Its setup runs first and its teardown runs last. See Lifecycle Order.
- Wrappers run after the access-control checks and before observers are notified. They don't run for OPTIONS requests, redirects, or WebSocket routes.
Classic Style#
As an alternative, implement RequestWrapper:
import 'package:revali_router/revali_router.dart';
class ServerTimingWrapper implements RequestWrapper {
const ServerTimingWrapper();
@override
WrapperResult wrap(Context context, NextResponse next) async {
final watch = Stopwatch()..start();
try {
return await next();
} finally {
print('${context.request.uri} took ${watch.elapsedMilliseconds}ms');
}
}
}
Apply it with @ServerTimingWrapper(), or by type with @Wrappers([ServerTimingWrapper]).