diff --git a/docs_src/custom_docs_ui/tutorial002.py b/docs_src/custom_docs_ui/tutorial002.py index 23ea368f8..9925d5236 100644 --- a/docs_src/custom_docs_ui/tutorial002.py +++ b/docs_src/custom_docs_ui/tutorial002.py @@ -1,4 +1,4 @@ -from fastapi import FastAPI +from fastapi import FastAPI, Request from fastapi.openapi.docs import ( get_redoc_html, get_swagger_ui_html, @@ -12,13 +12,14 @@ app.mount("/static", StaticFiles(directory="static"), name="static") @app.get("/docs", include_in_schema=False) -async def custom_swagger_ui_html(): +async def custom_swagger_ui_html(req: Request): + root_path = req.scope.get("root_path", "").rstrip("/") return get_swagger_ui_html( - openapi_url=app.openapi_url, + openapi_url=f"{root_path}/{app.openapi_url}", title=app.title + " - Swagger UI", oauth2_redirect_url=app.swagger_ui_oauth2_redirect_url, - swagger_js_url="/static/swagger-ui-bundle.js", - swagger_css_url="/static/swagger-ui.css", + swagger_js_url=f"{root_path}/static/swagger-ui-bundle.js", + swagger_css_url=f"{root_path}/static/swagger-ui.css", ) @@ -28,11 +29,12 @@ async def swagger_ui_redirect(): @app.get("/redoc", include_in_schema=False) -async def redoc_html(): +async def redoc_html(req: Request): + root_path = req.scope.get("root_path", "").rstrip("/") return get_redoc_html( - openapi_url=app.openapi_url, + openapi_url=f"{root_path}/{app.openapi_url}", title=app.title + " - ReDoc", - redoc_js_url="/static/redoc.standalone.js", + redoc_js_url=f"{root_path}/static/redoc.standalone.js", ) diff --git a/tests/test_offline_docs/static/redoc.js b/tests/test_offline_docs/static/redoc.js new file mode 100644 index 000000000..f05278909 --- /dev/null +++ b/tests/test_offline_docs/static/redoc.js @@ -0,0 +1,3 @@ +function bar() { + return "bar" +} \ No newline at end of file diff --git a/tests/test_offline_docs/test_root_path_with_static_mount.py b/tests/test_offline_docs/test_root_path_with_static_mount.py index 97d00fe42..ebe203492 100644 --- a/tests/test_offline_docs/test_root_path_with_static_mount.py +++ b/tests/test_offline_docs/test_root_path_with_static_mount.py @@ -1,36 +1,62 @@ -from fastapi import FastAPI +import pytest + +from fastapi import FastAPI, Request from fastapi.staticfiles import StaticFiles -from fastapi.openapi.docs import get_swagger_ui_html +from fastapi.openapi.docs import get_swagger_ui_html, get_redoc_html from fastapi.testclient import TestClient -root_path = "/api" -app = FastAPI( - title="FastAPI", - root_path=root_path, - docs_url=None, - redoc_url=None, +@pytest.mark.parametrize( + ["root_path", "using_test_client"], + [ + ("/api", True), + ("/api", False), + ("", True), + ("", False), + ] ) - -app.mount("/static", StaticFiles(directory="tests/test_offline_docs/static"), name="static") - -@app.get("/") -async def custom_swagger_ui_html(): - """ - Sets up a localized version of the Swagger (OpenAPI) docs that can be run without assets from the Internet. - """ - - return get_swagger_ui_html( - openapi_url="/openapi.json", - title=app.title, - swagger_js_url="/static/swagger.js", - swagger_css_url="/static/swagger.css", +def test_swagger_docs_with_static_assets( + root_path: str, + using_test_client: bool, +): + app_kwargs = {} + client_kwargs = {} + if not using_test_client: + app_kwargs = { + "root_path": root_path + } + if using_test_client: + client_kwargs = { + "root_path": root_path + } + + app = FastAPI( + title="FastAPI", + docs_url=None, + redoc_url=None, + **app_kwargs, ) + + app.mount("/static", StaticFiles(directory="tests/test_offline_docs/static"), name="static") + + @app.get("/") + async def custom_swagger_ui_html( + req: Request + ): + """ + Sets up a localized version of the Swagger (OpenAPI) docs that can be run without assets from the Internet. + """ + root_path = req.scope.get("root_path", "").rstrip("/") + return get_swagger_ui_html( + openapi_url=f"{root_path}/openapi.json", + title=app.title, + swagger_js_url=f"{root_path}/static/swagger.js", + swagger_css_url=f"{root_path}/static/swagger.css", + ) -client = TestClient(app) + client = TestClient(app, **client_kwargs) -def test_static_assets(): response = client.get("/") assert response.status_code == 200 assert response.headers["Content-Type"] == "text/html; charset=utf-8" @@ -39,13 +65,80 @@ def test_static_assets(): response = client.get("/openapi.json") assert response.status_code == 200 - response = client.get("/static/swagger.js") + response = client.get(f"{root_path}/openapi.json") + assert response.status_code == 200 + + response = client.get(f"{root_path}/static/swagger.js") assert response.status_code == 200 - response = client.get("/static/swagger.css") + response = client.get(f"{root_path}/static/swagger.css") assert response.status_code == 200 - assert "/static/swagger.js" in swagger_html - assert "/static/swagger.css" in swagger_html + assert f"{root_path}/static/swagger.js" in swagger_html + assert f"{root_path}/static/swagger.css" in swagger_html + + +@pytest.mark.parametrize( + ["root_path", "using_test_client"], + [ + ("/api", True), + ("/api", False), + ("", True), + ("", False), + ] +) +def test_redoc_docs_with_static_assets( + root_path: str, + using_test_client: bool, +): + app_kwargs = {} + client_kwargs = {} + if not using_test_client: + app_kwargs = { + "root_path": root_path + } + if using_test_client: + client_kwargs = { + "root_path": root_path + } + + app = FastAPI( + title="FastAPI", + docs_url=None, + redoc_url=None, + **app_kwargs, + ) + + app.mount("/static", StaticFiles(directory="tests/test_offline_docs/static"), name="static") + + @app.get("/") + async def custom_redoc_html( + req: Request + ): + """ + Sets up a localized version of the Swagger (OpenAPI) docs that can be run without assets from the Internet. + """ + root_path = req.scope.get("root_path", "").rstrip("/") + return get_redoc_html( + openapi_url=f"{root_path}/openapi.json", + title=app.title, + redoc_js_url=f"{root_path}/static/redoc.js", + ) + client = TestClient(app, **client_kwargs) + + response = client.get("/") + assert response.status_code == 200 + assert response.headers["Content-Type"] == "text/html; charset=utf-8" + redoc_html = response.text + + response = client.get("/openapi.json") + assert response.status_code == 200 + + response = client.get(f"{root_path}/openapi.json") + assert response.status_code == 200 + + response = client.get(f"{root_path}/static/redoc.js") + assert response.status_code == 200 + assert f"{root_path}/static/redoc.js" in redoc_html \ No newline at end of file