Documentation
Route Middleware
Attach middleware to specific routes, like leaves to their branches.
Route middleware is @middleware, @middleware.before(), or @middleware.after() limited by a specific route, method, or both.
Route middleware is declared at module level, so the function receives request and call. If the same decorator is used inside a @REST class, Autumn recognizes the controller method and registers controller middleware instead.
from autumn import Request, middleware
@middleware(
path = '/users/current/{name:str}',
method = 'GET'
)
async def current_user_guard(request: Request, call):
print('Current user route')
return await call(request)
This middleware runs only for requests whose path matches the template, for example:
GET /users/current/dima
Filtering by path
The path parameter sets a route template.
@middleware(path = '/users/current/{name:str}')
async def only_current_user(request: Request, call):
return await call(request)
Path parameters in middleware templates are written the same way as routes:
'/users/current/{name:str}'
When matching middleware, Autumn replaces segments in curly braces with [^/]+, so the middleware applies to any value in that segment.
GET /users/current/dima
GET /users/current/alex
Filtering by method
The method parameter limits middleware to an HTTP method.
@middleware(method = 'POST')
async def only_post(request: Request, call):
return await call(request)
This middleware applies to POST requests.
Usually method is used together with path to bind middleware to a specific handler.
@middleware.after(path = '/users/test', method = 'POST')
async def log_create_user(request: Request, response):
print('<< Response sent:', response.status)
return response
path and method can be a string or a list/tuple of strings.
@middleware(
path = ('/users', '/profiles'),
method = ['GET', 'POST']
)
async def users_or_profiles(request: Request, call):
return await call(request)
Before for One Route
@middleware.before(path = ..., method = ...) is useful for checks before one route handler.
from autumn.response import JSONResponse
@middleware.before(path = '/admin/users', method = 'GET')
async def admin_guard(request: Request, call):
if request.header('authorization') is None:
return JSONResponse({ 'error': 'Unauthorized' }, status = 401)
return await call(request)
If middleware returns a response without calling call, the route handler is not called.
After for One Route
@middleware.after(path = ..., method = ...) is useful for logging or modifying the response of one route.
@middleware.after(path = '/users/test', method = 'POST')
async def stamp_create_user(request: Request, response):
response.headers['X-Route'] = 'create-user'
return response
Important Detail About path
Middleware is matched against the registered route path_template, not the original URL string.
For example, if the route is declared as:
@REST(prefix = '/users')
class UserController:
@get('/current/{name:str}')
async def current_name(self, name: str):
return { 'name': name }
then middleware must use the final template:
@middleware.before(path = '/users/current/{name:str}', method = 'GET')
async def test(request: Request, call):
return await call(request)
This is the form used in the example application.
When to Use Route Middleware
Use route middleware when logic applies to a few lifecycle points, but not the whole application:
- permission checks for a specific handler;
- logging a sensitive operation;
- adding a header to one route;
- temporary compatibility for an old API;
- targeted error handling.
If the logic applies to every method in one controller, controller middleware is usually more convenient.