# Middlewares Middlewares are functions called before the route handler. They have access to the `RequestContext` object and also to the `NextFunction` function, which is used to call the next middleware or the route handler. Serinus middlewares, for ease of use, follow the capabilities of the Express.js middlewares so they can perform the same tasks. ::: info To pass to the next middleware or route handler, you must call the `next` function. ::: To create a middleware, you must extends the `Middleware` class and implement the `use` method. ```dart import 'package:serinus/serinus.dart'; class LoggerMiddleware extends Middleware { @override Future use(ExecutionContext context, NextFunction next) async { print('Request received: ${context.request.method} ${context.request.url}'); return next(); } } ``` ## Dependency Injection Serinus middlewares share the same scope as the route handlers, so you can inject dependencies into them. So if a dependency is available in the route handler, it will be available in the middleware as well. ## Using Middlewares To use a middleware, you must override the `configure` method of the `Module` class. ```dart import 'package:serinus/serinus.dart'; class AppModule extends Module { const AppModule() : super(); @override void configure(MiddlewareConsumer consumer) { consumer .apply([LoggerMiddleware()]) .forRoutes([RouteInfo('/'),]); // You can also use wildcards like '/*' or '/users/*' } } ``` But you can also use a middleware linked to a specific `Controller`. ```dart import 'package:serinus/serinus.dart'; class AppModule extends Module { const AppModule() : super( controllers: [TestController()], ); @override void configure(MiddlewareConsumer consumer) { consumer .apply([LoggerMiddleware()]) .forControllers([TestController]); } } ``` In the example above the `LoggerMiddleware` will be called only for the routes defined in the `TestController`. ## Blocking requests Middlewares in Serinus can also block requests by three methods: - Throwing an exception (This will block the execution of the following lifecycle methods) - Not calling the `next` function (This will block the whole request) - Calling the `next` method witha result (This will block the whole request) ```dart import 'package:serinus/serinus.dart'; class AuthMiddleware extends Middleware { AuthMiddleware() : super(routes: ['/']); @override Future use(ExecutionContext context, NextFunction next) async { if (context.request.headers['authorization'] != 'Bearer token') { context.res.statusCode = 401; return next('Unauthorized'); } return next(); } } ``` ## Shelf Middlewares > But what if I want to use a Shelf middleware? No problem! You can use Shelf middlewares in Serinus as well and by doing so you can use the vast amount of middlewares available in the Shelf ecosystem. ```dart import 'package:serinus/serinus.dart'; class UserModule extends Module { const UserModule() : super(); @override void configure(MiddlewareConsumer consumer) { consumer .apply([Middleware.shelf(shelfMiddleware)]) // You can also pass Shelf handlers .forRoutes([RouteInfo('*'),]); } } ``` The `Middleware.shelf` factory constructor will convert the Shelf middleware to a Serinus middleware and will be called before the route handlers in the module and in the submodules but there is a catch! Shelf Middlewares can block the request without Serinus knowing it, so to prevent this, if you know that the Shelf middleware will block the request, you can set the `ignoreResponse` parameter to `false` to the `Middleware.shelf` factory constructor. ```dart import 'package:serinus/serinus.dart'; class UserModule extends Module { const UserModule() : super(); @override void configure(MiddlewareConsumer consumer) { consumer .apply([Middleware.shelf(shelfMiddleware, ignoreResponse: false)]) // You can also pass Shelf handlers .forRoutes([RouteInfo('*'),]); } } ```