fastapi

Is there a FastAPI way to access current Request data globally?


Within the FastAPI framework:

While request data can certainly be passed around as an argument, I would like to know if it is possible for a function to access information about the current request without being passed an argument.

Disclaimer: I do not think global access to Request data a good practice, and yet I have a use case where it would be very good to be able to do.


Solution

  • A solution provided here defines a context manager, that you can access globally. For each request, you are extracting the relevant information (like headers) & pass it to the context manager.

    Since fastapi is built with Starlette, you can use the library starlette-context. It is creating a context object that you can use without passing it as argument. The main caveat is that you still need to pass a request object to all your routes.

    EDIT: In starlette-context==0.3.0 new middleware has been added. Starlette team started to discourage (here) the use of their BaseHTTPMiddleware, in particulary for StreamingResponse/FileResponse endpoints. You might want to use RawContextMiddleware which also doesn't require the request object but it's experimental as there is no documentation in Starlette for writing custom middleware without the interface. But it seems to be working.

    Sample code from this lib to illustrate:

    import uvicorn
    from fastapi import FastAPI
    from starlette.requests import Request
    from starlette.responses import JSONResponse
    from starlette.middleware import Middleware
    
    from starlette_context import context, plugins
    from starlette_context.middleware import RawContextMiddleware
    
    middleware = [
        Middleware(
            RawContextMiddleware,
            plugins=(
                plugins.RequestIdPlugin(),
                plugins.CorrelationIdPlugin()
            )
        )
    ]
    
    app = FastAPI(debug=True, middleware=middleware)
    
    
    @app.route('/')
    async def index(request: Request):  # This argument is still needed here
        return JSONResponse(context.data)  # Your context data
    
    
    uvicorn.run(app, host="0.0.0.0")