diff --git a/docs/en/docs/how-to/custom-docs-ui-assets.md b/docs/en/docs/how-to/custom-docs-ui-assets.md index 61a97dca2b..d7ed274b3b 100644 --- a/docs/en/docs/how-to/custom-docs-ui-assets.md +++ b/docs/en/docs/how-to/custom-docs-ui-assets.md @@ -34,7 +34,7 @@ You can reuse FastAPI's internal functions to create the HTML pages for the docs And similarly for ReDoc... -{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[2:6,11:19,22:24,27:33] *} +{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[2:6,11:20,23:25,28:35] *} /// tip @@ -50,7 +50,7 @@ Swagger UI will handle it behind the scenes for you, but it needs this "redirect Now, to be able to test that everything works, create a *path operation*: -{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[36:38] *} +{* ../../docs_src/custom_docs_ui/tutorial001_py39.py hl[38:40] *} ### Test it { #test-it } @@ -160,7 +160,7 @@ Again, you can reuse FastAPI's internal functions to create the HTML pages for t And similarly for ReDoc... -{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[2:6,14:22,25:27,30:36] *} +{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[2:6,14:23,26:28,31:38] *} /// tip @@ -176,7 +176,7 @@ Swagger UI will handle it behind the scenes for you, but it needs this "redirect Now, to be able to test that everything works, create a *path operation*: -{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[39:41] *} +{* ../../docs_src/custom_docs_ui/tutorial002_py39.py hl[41:43] *} ### Test Static Files UI { #test-static-files-ui } diff --git a/docs_src/custom_docs_ui/tutorial001_py39.py b/docs_src/custom_docs_ui/tutorial001_py39.py index 1cfcce19aa..776256dc50 100644 --- a/docs_src/custom_docs_ui/tutorial001_py39.py +++ b/docs_src/custom_docs_ui/tutorial001_py39.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, @@ -9,11 +9,12 @@ app = FastAPI(docs_url=None, redoc_url=None) @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, + oauth2_redirect_url=f"{root_path}{app.swagger_ui_oauth2_redirect_url}", swagger_js_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js", swagger_css_url="https://unpkg.com/swagger-ui-dist@5/swagger-ui.css", ) @@ -25,9 +26,10 @@ 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="https://unpkg.com/redoc@2/bundles/redoc.standalone.js", ) diff --git a/docs_src/custom_docs_ui/tutorial002_py39.py b/docs_src/custom_docs_ui/tutorial002_py39.py index 23ea368f8b..b2b61204d6 100644 --- a/docs_src/custom_docs_ui/tutorial002_py39.py +++ b/docs_src/custom_docs_ui/tutorial002_py39.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", + oauth2_redirect_url=f"{root_path}{app.swagger_ui_oauth2_redirect_url}", + 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_tutorial/test_custom_docs_ui/test_tutorial001.py b/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py index 1816e5d975..d4b9288652 100644 --- a/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py +++ b/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py @@ -5,38 +5,61 @@ import pytest from fastapi.testclient import TestClient -@pytest.fixture(scope="module") -def client(): +@pytest.fixture( + params=["", "/api"], + ids=["Without path prefix", "With /api path prefix"], +) +def path_prefix(request: pytest.FixtureRequest): + return request.param + + +@pytest.fixture +def client(path_prefix: str): static_dir: Path = Path(os.getcwd()) / "static" print(static_dir) static_dir.mkdir(exist_ok=True) from docs_src.custom_docs_ui.tutorial001_py39 import app - with TestClient(app) as client: + with TestClient(app, root_path=path_prefix, base_url="http://server") as client: yield client + static_dir.rmdir() -def test_swagger_ui_html(client: TestClient): - response = client.get("/docs") +def test_swagger_ui_html(client: TestClient, path_prefix: str): + response = client.get(f"{path_prefix}/docs") + assert response.request.url == f"http://server{path_prefix}/docs" assert response.status_code == 200, response.text assert "https://unpkg.com/swagger-ui-dist@5/swagger-ui-bundle.js" in response.text assert "https://unpkg.com/swagger-ui-dist@5/swagger-ui.css" in response.text + assert f"{path_prefix}/openapi.json" in response.text + assert f"{path_prefix}/docs/oauth2-redirect" in response.text -def test_swagger_ui_oauth2_redirect_html(client: TestClient): - response = client.get("/docs/oauth2-redirect") +def test_openapi_json(client: TestClient, path_prefix: str): + response = client.get(f"{path_prefix}/openapi.json") + assert response.request.url == f"http://server{path_prefix}/openapi.json" + assert response.status_code == 200, response.text + assert response.json()["openapi"] == "3.1.0" + + +def test_swagger_ui_oauth2_redirect_html(client: TestClient, path_prefix: str): + response = client.get(f"{path_prefix}/docs/oauth2-redirect") + assert response.request.url == f"http://server{path_prefix}/docs/oauth2-redirect" assert response.status_code == 200, response.text assert "window.opener.swaggerUIRedirectOauth2" in response.text -def test_redoc_html(client: TestClient): - response = client.get("/redoc") +def test_redoc_html(client: TestClient, path_prefix: str): + response = client.get(f"{path_prefix}/redoc") + assert response.request.url == f"http://server{path_prefix}/redoc" assert response.status_code == 200, response.text assert "https://unpkg.com/redoc@2/bundles/redoc.standalone.js" in response.text + assert f"{path_prefix}/openapi.json" in response.text -def test_api(client: TestClient): - response = client.get("/users/john") +def test_api(client: TestClient, path_prefix: str): + response = client.get(f"{path_prefix}/users/john") + assert response.request.url == f"http://server{path_prefix}/users/john" assert response.status_code == 200, response.text assert response.json()["message"] == "Hello john" diff --git a/tests/test_tutorial/test_custom_docs_ui/test_tutorial002.py b/tests/test_tutorial/test_custom_docs_ui/test_tutorial002.py index e8b7eb7aa3..e9eb420676 100644 --- a/tests/test_tutorial/test_custom_docs_ui/test_tutorial002.py +++ b/tests/test_tutorial/test_custom_docs_ui/test_tutorial002.py @@ -5,38 +5,60 @@ import pytest from fastapi.testclient import TestClient -@pytest.fixture(scope="module") -def client(): +@pytest.fixture( + params=["", "/api"], + ids=["Without path prefix", "With /api path prefix"], +) +def path_prefix(request: pytest.FixtureRequest): + return request.param + + +@pytest.fixture +def client(path_prefix: str): static_dir: Path = Path(os.getcwd()) / "static" print(static_dir) static_dir.mkdir(exist_ok=True) from docs_src.custom_docs_ui.tutorial002_py39 import app - with TestClient(app) as client: + with TestClient(app, root_path=path_prefix, base_url="http://server") as client: yield client + static_dir.rmdir() -def test_swagger_ui_html(client: TestClient): - response = client.get("/docs") +def test_swagger_ui_html(client: TestClient, path_prefix: str): + response = client.get(f"{path_prefix}/docs") + assert response.request.url == f"http://server{path_prefix}/docs" assert response.status_code == 200, response.text - assert "/static/swagger-ui-bundle.js" in response.text - assert "/static/swagger-ui.css" in response.text + assert f"{path_prefix}/static/swagger-ui-bundle.js" in response.text + assert f"{path_prefix}/static/swagger-ui.css" in response.text + assert f"{path_prefix}/docs/oauth2-redirect" in response.text -def test_swagger_ui_oauth2_redirect_html(client: TestClient): - response = client.get("/docs/oauth2-redirect") +def test_openapi_json(client: TestClient, path_prefix: str): + response = client.get(f"{path_prefix}/openapi.json") + assert response.request.url == f"http://server{path_prefix}/openapi.json" + assert response.status_code == 200, response.text + assert response.json()["openapi"] == "3.1.0" + + +def test_swagger_ui_oauth2_redirect_html(client: TestClient, path_prefix: str): + response = client.get(f"{path_prefix}/docs/oauth2-redirect") + assert response.request.url == f"http://server{path_prefix}/docs/oauth2-redirect" assert response.status_code == 200, response.text assert "window.opener.swaggerUIRedirectOauth2" in response.text -def test_redoc_html(client: TestClient): - response = client.get("/redoc") +def test_redoc_html(client: TestClient, path_prefix: str): + response = client.get(f"{path_prefix}/redoc") + assert response.request.url == f"http://server{path_prefix}/redoc" assert response.status_code == 200, response.text - assert "/static/redoc.standalone.js" in response.text + assert f"{path_prefix}/static/redoc.standalone.js" in response.text + assert f"{path_prefix}/openapi.json" in response.text -def test_api(client: TestClient): - response = client.get("/users/john") +def test_api(client: TestClient, path_prefix: str): + response = client.get(f"{path_prefix}/users/john") + assert response.request.url == f"http://server{path_prefix}/users/john" assert response.status_code == 200, response.text assert response.json()["message"] == "Hello john"