@@ -2345,19 +2345,36 @@ def traceback_exception_handler(request: Request, exc: Exception):
23452345 )
23462346
23472347
2348- @versioned_app .middleware ("http" )
2349- async def redirect_http_requests (request : Request , call_next ):
2350- """Redirect request with version prefix when no version is provided"""
2351- response = None
2352- path = request .scope ["path" ]
2353- match = re .match (r"^/(v[\d.]+)" , path )
2354- if match :
2355- prefix = match .group (1 )
2356- if prefix not in API_VERSIONS :
2357- response = PlainTextResponse (
2358- f"Unsupported API version: { prefix } " ,
2359- status_code = status .HTTP_400_BAD_REQUEST ,
2360- )
2361- elif not path .startswith ("/latest" ):
2362- request .scope ["path" ] = "/latest" + path
2363- return response or await call_next (request )
2348+ class VersionRedirectMiddleware :
2349+ """Pure ASGI middleware to redirect requests with version prefix.
2350+
2351+ Avoids BaseHTTPMiddleware which can corrupt the request scope
2352+ (fastapi_inner_astack not found in request scope).
2353+ """
2354+
2355+ def __init__ (self , app ):
2356+ self .app = app
2357+
2358+ async def __call__ (self , scope , receive , send ):
2359+ if scope ["type" ] != "http" :
2360+ await self .app (scope , receive , send )
2361+ return
2362+
2363+ path = scope ["path" ]
2364+ match = re .match (r"^/(v[\d.]+)" , path )
2365+ if match :
2366+ prefix = match .group (1 )
2367+ if prefix not in API_VERSIONS :
2368+ response = PlainTextResponse (
2369+ f"Unsupported API version: { prefix } " ,
2370+ status_code = status .HTTP_400_BAD_REQUEST ,
2371+ )
2372+ await response (scope , receive , send )
2373+ return
2374+ elif not path .startswith ("/latest" ):
2375+ scope ["path" ] = "/latest" + path
2376+
2377+ await self .app (scope , receive , send )
2378+
2379+
2380+ versioned_app .add_middleware (VersionRedirectMiddleware )
0 commit comments