Skip to content

Commit c00c8fa

Browse files
committed
fastapi: bugfix after upgrade, replace fastapi-versioning by native include_router.
fastapi-versioning transplants route objects by directly appending them to sub-app router.routes. In New FastAPI + Starlette this doesnt work properly. Let's replace VersionedFastAPI with include_router, which properly re-creates APIRoute objects through APIRoute.__init__ — ensuring FastAPI's request_response wrapper is used. P.S. fastapi-versioning and fastapi-users are both poorly maintained and source of many issues. Signed-off-by: Denys Fedoryshchenko <denys.f@collabora.com>
1 parent b90be92 commit c00c8fa

File tree

3 files changed

+27
-35
lines changed

3 files changed

+27
-35
lines changed

api/main.py

Lines changed: 23 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@
4141
JSONResponse,
4242
PlainTextResponse,
4343
)
44+
from fastapi.routing import APIRoute, APIRouter
4445
from fastapi.security import OAuth2PasswordRequestForm
4546
from fastapi_pagination import add_pagination
4647
from fastapi_users import FastAPIUsers
47-
from fastapi_versioning import VersionedFastAPI
4848
from jose import jwt
4949
from jose.exceptions import JWTError
5050
from kernelci.api.models import (
@@ -2300,12 +2300,19 @@ async def purge_handler(
23002300
return await purge_old_nodes(age_days=days, batch_size=batch_size)
23012301

23022302

2303-
versioned_app = VersionedFastAPI(
2304-
app,
2305-
version_format="{major}",
2306-
prefix_format="/v{major}",
2307-
enable_latest=True,
2308-
default_version=(0, 0),
2303+
# Build versioned app using include_router instead of fastapi-versioning.
2304+
# VersionedFastAPI (fastapi-versioning==0.10.0) is incompatible with
2305+
# FastAPI >= 0.118.0: it transplants route objects by directly appending
2306+
# to sub-app router.routes, which bypasses FastAPI's request_response
2307+
# wrapper and causes 'fastapi_inner_astack not found in request scope'.
2308+
# Using include_router re-creates APIRoute objects properly.
2309+
_api_router = APIRouter()
2310+
for _route in app.routes:
2311+
if isinstance(_route, APIRoute):
2312+
_api_router.routes.append(_route)
2313+
2314+
versioned_app = FastAPI(
2315+
title=app.title,
23092316
on_startup=[
23102317
pubsub_startup,
23112318
create_indexes,
@@ -2315,9 +2322,10 @@ async def purge_handler(
23152322
],
23162323
)
23172324

2325+
versioned_app.include_router(_api_router, prefix="/v0")
2326+
versioned_app.include_router(_api_router, prefix="/latest")
2327+
23182328

2319-
# traceback_exception_handler is a global exception handler that will be
2320-
# triggered for all exceptions that are not handled by specific exception
23212329
def traceback_exception_handler(request: Request, exc: Exception):
23222330
"""Global exception handler to print traceback"""
23232331
print(f"Exception: {exc}")
@@ -2328,29 +2336,15 @@ def traceback_exception_handler(request: Request, exc: Exception):
23282336
)
23292337

23302338

2331-
# Workaround to use global exception handlers for versioned API.
2332-
# The issue has already been reported here:
2333-
# https://github.com/DeanWay/fastapi-versioning/issues/30
2334-
for sub_app in versioned_app.routes:
2335-
if hasattr(sub_app.app, "add_exception_handler"):
2336-
sub_app.app.add_exception_handler(
2337-
ValueError, value_error_exception_handler
2338-
)
2339-
sub_app.app.add_exception_handler(
2340-
errors.InvalidId, invalid_id_exception_handler
2341-
)
2342-
# print traceback for all other exceptions
2343-
sub_app.app.add_exception_handler(
2344-
Exception, traceback_exception_handler
2345-
)
2339+
versioned_app.add_exception_handler(ValueError, value_error_exception_handler)
2340+
versioned_app.add_exception_handler(
2341+
errors.InvalidId, invalid_id_exception_handler
2342+
)
2343+
versioned_app.add_exception_handler(Exception, traceback_exception_handler)
23462344

23472345

23482346
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-
"""
2347+
"""Pure ASGI middleware to redirect requests with version prefix."""
23542348

23552349
def __init__(self, app):
23562350
self.app = app

docker/api/requirements.txt

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
cloudevents==1.9.0
2-
beanie == 1.29.0
3-
fastapi[all]==0.115.0
1+
cloudevents==2.0.0
2+
beanie==1.29.0
3+
fastapi[all]==0.135.3
44
fastapi-pagination==0.12.30
5-
fastapi-users[beanie, oauth]==15.0.2
6-
fastapi-versioning==0.10.0
5+
fastapi-users[beanie, oauth]==15.0.5
76
MarkupSafe==2.0.1
87
motor==3.6.0
98
pymongo==4.9.0

pyproject.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ dependencies = [
2121
"fastapi[all] == 0.135.3",
2222
"fastapi-pagination == 0.12.30",
2323
"fastapi-users[beanie, oauth] == 15.0.5",
24-
"fastapi-versioning == 0.10.0",
2524
"MarkupSafe == 2.0.1",
2625
"motor == 3.6.0",
2726
"pymongo == 4.9.0",

0 commit comments

Comments
 (0)