Hello,
Is it possible to register functions to be run before and after a request, similar to in flask?
Are you familiar with how this works, and is there an equivalent in FastAPI/Starlette?
I haven't used flask much, but looking through the flask docs a little, this seems to be the same concept as middleware.
Here are the middleware docs for FastAPI, and for starlette.
For example, looking at an example from the SQL Databases page from the FastAPI docs (linked from the middleware link above), here's a way to use this to handle a database session at the start and end of each request:
@app.middleware("http")
async def db_session_middleware(request: Request, call_next):
response = Response("Internal server error", status_code=500)
try:
request.state.db = SessionLocal()
response = await call_next(request)
finally:
request.state.db.close()
return response
I think that flask.before_request basically corresponds to the code prior to the response = await call_next(request) line, and flask.after_request corresponds to the part afterward.
That's perfect, and very neat in comparison.
My use case is to add JSON logging which takes context from the request/response.
I was able to achieve it with the following example
import structlog
from fastapi import FastAPI
from starlette.requests import Request
from starlette.responses import Response
structlog.configure(
processors=[
structlog.processors.JSONRenderer()
]
)
logger = structlog.get_logger()
app = FastAPI()
@app.middleware('http')
async def logging_middleware(request: Request, call_next):
response = Response("Internal server error", status_code=500)
log = logger.bind(
url=str(request.url),
method=request.method,
)
try:
response: Response = await call_next(request)
finally:
log.msg(
status=response.status_code,
)
return response
Thanks for the help as always @dmontagu ! :cake: :tada:
Thanks @cetanu for reporting back and closing the issue :heavy_check_mark:
@cetanu does that logging with structlog work correctly? I'm finding that, parallel requests mix up the context - where bound context (in your case, url and method) end up spanning across the different request/response cycle. Even when I'm using structlog's threaded local dict + context manager.
@hongymagic
This is something I set up for a colleague, I haven't heard any reports of such behavior and from what I've seen it seems to be working as expected... As long as you're not accidentally binding to a logger used in an outer scope I imagine it should be okay?
It was a pretty similar setup to above, except in our case we use (or generate) a X-Request-Id and add it to the structlog's context.
We ended up solving it, see: https://github.com/hynek/structlog/issues/222
Most helpful comment
I haven't used flask much, but looking through the flask docs a little, this seems to be the same concept as middleware.
Here are the middleware docs for FastAPI, and for starlette.
For example, looking at an example from the SQL Databases page from the FastAPI docs (linked from the middleware link above), here's a way to use this to handle a database session at the start and end of each request:
I think that flask.before_request basically corresponds to the code prior to the
response = await call_next(request)line, and flask.after_request corresponds to the part afterward.