Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

fastapi

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.

like image 874
Andrew Allaire Avatar asked Jul 25 '19 14:07

Andrew Allaire


Video Answer


1 Answers

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 ContextMiddleware

middleware = [
    Middleware(
        ContextMiddleware,
        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")
like image 129
Colin Le Nost Avatar answered Oct 12 '22 22:10

Colin Le Nost