Search code examples
fastapistarletteasgi

Get path template from starlette request from a middleware


I am building a middleware to log calls to functions among other things. I have read about FastAPI: How to get raw URL path from request?, which suggests to use request.scope.get("route"), which works when used in the endpoint function. However, in the middleware, request.scope has no attribute "route". I am unsure of what a scope really is and why it changes in the middleware, but how can i work around this ?

@app.get("/success/{id}", status_code=201)
def success():
    return 

app.add_middleware(RequestInfo)

from starlette.middleware.base import BaseHTTPMiddleware
from fastapi import Request

class RequestInfo(BaseHTTPMiddleware):
    async def dispatch(self, request: Request, call_next):
         logger.info("Hello")
         # Doing some things

Solution

  • Middlewares are called before the routing (https://github.com/encode/starlette/issues/685#issuecomment-550240999). So, in that point there is no easy way to get this information.

    Consider using custom APIRoute instead. It's quite similar to middleware in functionality, but it's called after the routing.

    from typing import Callable
    from fastapi import FastAPI
    from fastapi.routing import APIRoute
    
    class LoggingRouter(APIRoute):
        def get_route_handler(self) -> Callable:
            print(self.dependant.path)
            return super().get_route_handler()
    
    app = FastAPI()
    app.router.route_class = LoggingRouter
    
    @app.get("/success/{id}", status_code=201)
    def success(id: str):
        return id
    

    Read more about custom APIRoute: https://fastapi.tiangolo.com/how-to/custom-request-and-route/