"""One API, addressed two ways. Every route is mounted once, under `/api/v1`. `/api/...` is the same route reached by its old address: the web app in this repository has thousands of call sites written that way, and an address that has been shipped is a promise. The alias is a path rewrite rather than a second `include_router`, for two reasons. A second mount would double every path in the OpenAPI document, so the contract an app is written against would describe each endpoint twice; and two mounts can drift, while a rewrite cannot — there is only ever one route. What this deliberately does *not* do is redirect. A 307 back to `/api/v1/...` would break every non-browser client that does not follow redirects on POST, and would leak the version into logs and bookmarks for no gain. """ from starlette.types import ASGIApp, Receive, Scope, Send #: Anything under here is the API. `/uploads` and the docs are not. API_ROOT = "/api" CURRENT = "v1" VERSIONED_ROOT = f"{API_ROOT}/{CURRENT}" #: Addresses under /api that are not versioned routes and must pass untouched. #: Kept explicit: a rewrite that silently swallowed one of these would be a 404 #: with no obvious cause — which is exactly what happened to /api/health the #: first time this shipped. A liveness check is pointed at by monitoring that #: nobody edits for a year; it does not move when the API is versioned. PASSTHROUGH = ("/api/docs", "/api/redoc", "/api/openapi.json", "/api/health") def is_versioned(path: str) -> bool: return path == VERSIONED_ROOT or path.startswith(VERSIONED_ROOT + "/") class VersionAlias: """Rewrite `/api/x` to `/api/v1/x` before routing sees it.""" def __init__(self, app: ASGIApp) -> None: self.app = app async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None: if scope["type"] == "http": path = scope.get("path", "") if (path.startswith(API_ROOT + "/") and not is_versioned(path) and path not in PASSTHROUGH): scope = dict(scope) scope["path"] = VERSIONED_ROOT + path[len(API_ROOT):] # Kept so a route, a log line or an error can say which address # the caller actually used. scope["raw_path"] = scope["path"].encode() scope["api_alias"] = True await self.app(scope, receive, send)