This commit is contained in:
Motov Yurii 2026-02-17 10:01:27 +00:00 committed by GitHub
commit e9b1b22eca
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 73 additions and 0 deletions

View File

@ -1133,6 +1133,9 @@ class FastAPI(Starlette):
scope["root_path"] = self.root_path
await super().__call__(scope, receive, send)
def mount(self, path: str, app: ASGIApp, name: str | None = None) -> None:
self.router._mount(path, app=app, name=name)
def add_api_route(
self,
path: str,

View File

@ -74,6 +74,7 @@ from starlette.routing import (
get_name,
)
from starlette.routing import Mount as Mount # noqa
from starlette.staticfiles import StaticFiles
from starlette.types import AppType, ASGIApp, Lifespan, Receive, Scope, Send
from starlette.websockets import WebSocket
from typing_extensions import deprecated
@ -993,6 +994,20 @@ class APIRouter(routing.Router):
self.default_response_class = default_response_class
self.generate_unique_id_function = generate_unique_id_function
def mount(self, path: str, app: ASGIApp, name: str | None = None) -> None:
"""
Mount a StaticFiles instance.
Will raise a FastAPIError exception if app is not an instance of StaticFiles.
"""
if not isinstance(app, StaticFiles):
raise FastAPIError(
"APIRouter does not support mounting ASGI applications other than StaticFiles."
)
self._mount(path=self.prefix + path, app=app, name=name)
def _mount(self, path: str, app: ASGIApp, name: str | None = None) -> None:
super().mount(path=path, app=app, name=name)
def route(
self,
path: str,
@ -1489,6 +1504,11 @@ class APIRouter(routing.Router):
self.add_websocket_route(
prefix + route.path, route.endpoint, name=route.name
)
elif ( # fmt: skip
isinstance(route, routing.Mount) and isinstance(route.app, StaticFiles)
):
self.mount(prefix + route.path, route.app, name=route.name)
for handler in router.on_startup:
self.add_event_handler("startup", handler)
for handler in router.on_shutdown:

View File

@ -0,0 +1,50 @@
from pathlib import Path
import pytest
from fastapi import APIRouter, FastAPI
from fastapi.exceptions import FastAPIError
from fastapi.staticfiles import StaticFiles
from fastapi.testclient import TestClient
@pytest.mark.parametrize("root_path", ["", "/v1"])
@pytest.mark.parametrize(
("router_prefix", "include_prefix", "request_prefix"),
[
("", "", ""),
("/router", "", "/router"),
("", "/router_1", "/router_1"),
("/router", "/router_1", "/router_1/router"),
],
)
def test_mount_static_files_to_apirouter(
tmp_path: Path,
root_path: str,
router_prefix: str,
include_prefix: str,
request_prefix: str,
):
static_asset = tmp_path / "index.html"
static_asset.write_text("Hello, World!")
router = APIRouter(prefix=router_prefix)
router.mount("/static", StaticFiles(directory=tmp_path), name="static")
app = FastAPI(root_path=root_path or None)
app.include_router(router, prefix=include_prefix)
client = TestClient(app)
response = client.get(f"{root_path}{request_prefix}/static/index.html")
assert response.status_code == 200
assert response.text == "Hello, World!"
def test_mount_app_to_apirouter_raises():
router = APIRouter()
sub_app = FastAPI()
with pytest.raises(
FastAPIError,
match="APIRouter does not support mounting ASGI applications other than StaticFiles.",
):
router.mount("/sub", sub_app)