tomwojcik/starlette-context

Can't use http middleware

rahul-agarwal-savii opened this issue · 1 comments

I tried using starlette-context and it solves most of my problems as a near to perfect equivalent for Flask g.
Now I am facing issue in setting the request_id in the FastAPI's "http" middleware, my main.py is as follows:

import uuid

from fastapi import FastAPI, Request
from fastapi.encoders import jsonable_encoder
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from starlette_context import context
from starlette_context.middleware import RawContextMiddleware

from app.api.auth import security_router
from app.api.health import status_router
from app.api.v1.router import v1_router
from app.core.config import settings
from app.database import Base, engine
from app.exceptions import CustomException


def get_application():
    _app = FastAPI(title="referral-service")
    allowed_origins = [str(origin) for origin in settings.BACKEND_CORS_ORIGINS]

    _app.add_middleware(
        CORSMiddleware,
        allow_origins=allowed_origins,
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )
    _app.add_middleware(RawContextMiddleware)

    _app.include_router(v1_router, prefix="/api/v1")
    _app.include_router(security_router)
    _app.include_router(status_router)

    return _app


app = get_application()


@app.on_event("startup")
async def startup():
    # create db tables
    async with engine.begin() as conn:
        # await conn.run_sync(Base.metadata.drop_all)
        await conn.run_sync(Base.metadata.create_all)


@app.middleware("http")
async def set_request_context(request: Request, call_next):
    request_id = uuid.uuid4()
    context["request_id"] = request_id
    response = await call_next(request)
    return response


@app.exception_handler(CustomException)
async def custom_exception_handler(request: Request, exc: CustomException):
    return JSONResponse(
        jsonable_encoder(exc.response), status_code=exc.status_code
    )

When i run any of my route, it sends me the following error:

Traceback (most recent call last):
  File "/Users/rahulagarwal/Library/Caches/pypoetry/virtualenvs/referral-service-bzkw0PDN-py3.9/lib/python3.9/site-packages/uvicorn/protocols/http/h11_impl.py", line 366, in run_asgi
    result = await app(self.scope, self.receive, self.send)
  File "/Users/rahulagarwal/Library/Caches/pypoetry/virtualenvs/referral-service-bzkw0PDN-py3.9/lib/python3.9/site-packages/uvicorn/middleware/proxy_headers.py", line 75, in __call__
    return await self.app(scope, receive, send)
  File "/Users/rahulagarwal/Library/Caches/pypoetry/virtualenvs/referral-service-bzkw0PDN-py3.9/lib/python3.9/site-packages/fastapi/applications.py", line 261, in __call__
    await super().__call__(scope, receive, send)
  File "/Users/rahulagarwal/Library/Caches/pypoetry/virtualenvs/referral-service-bzkw0PDN-py3.9/lib/python3.9/site-packages/starlette/applications.py", line 112, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/Users/rahulagarwal/Library/Caches/pypoetry/virtualenvs/referral-service-bzkw0PDN-py3.9/lib/python3.9/site-packages/starlette/middleware/errors.py", line 181, in __call__
    raise exc
  File "/Users/rahulagarwal/Library/Caches/pypoetry/virtualenvs/referral-service-bzkw0PDN-py3.9/lib/python3.9/site-packages/starlette/middleware/errors.py", line 159, in __call__
    await self.app(scope, receive, _send)
  File "/Users/rahulagarwal/Library/Caches/pypoetry/virtualenvs/referral-service-bzkw0PDN-py3.9/lib/python3.9/site-packages/starlette/middleware/base.py", line 63, in __call__
    response = await self.dispatch_func(request, call_next)
  File "/Users/rahulagarwal/savii-code/referral-service/./app/main.py", line 58, in set_request_context
    context["request_id"] = request_id
  File "/opt/homebrew/Cellar/python@3.9/3.9.12/Frameworks/Python.framework/Versions/3.9/lib/python3.9/collections/__init__.py", line 1061, in __setitem__
    self.data[key] = item
  File "/Users/rahulagarwal/Library/Caches/pypoetry/virtualenvs/referral-service-bzkw0PDN-py3.9/lib/python3.9/site-packages/starlette_context/ctx.py", line 35, in data
    raise ContextDoesNotExistError
starlette_context.errors.ContextDoesNotExistError: You didn't use the required middleware or you're trying to access `context` object outside of the request-response cycle.

Am i doing something wrong with this? As far as I understand the middleware is a part of request-response cycle, so why am I getting the error that this is not part of the request-response cycle. Please help

Probably your set_request_context middleware is executed before the RawContextMiddleware.
There are plugins to populate the context with headers, especially request-id, you don't have to reinvent that.
https://starlette-context.readthedocs.io/en/latest/plugins.html