Skip to content

Commit 5785876

Browse files
committed
fix: pass root_path to FastAPI constructor instead of uvicorn
When lightspeed-stack runs behind 3scale with ROOT_PATH=/api/lightspeed, requests arrive with a doubled path prefix because uvicorn injects root_path into scope['root_path'] and Starlette concatenates it with the already-prefixed scope['path'] from 3scale. Move root_path from uvicorn.run() to the FastAPI() constructor, matching how rlsapi handles it. Signed-off-by: Major Hayden <major@redhat.com>
1 parent 5495f95 commit 5785876

3 files changed

Lines changed: 5 additions & 14 deletions

File tree

src/app/main.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ async def lifespan(_app: FastAPI) -> AsyncIterator[None]:
8484

8585

8686
app = FastAPI(
87+
root_path=configuration.service_configuration.root_path,
8788
title=f"{service_name} service - OpenAPI",
8889
summary=f"{service_name} service API specification.",
8990
description=f"{service_name} service API specification.",

src/runners/uvicorn.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def start_uvicorn(configuration: ServiceConfiguration) -> None:
1616
1717
Parameters:
1818
configuration (ServiceConfiguration): Configuration providing host,
19-
port, workers, `root_path`, and `tls_config` (including `tls_key_path`,
19+
port, workers, and `tls_config` (including `tls_key_path`,
2020
`tls_certificate_path`, and `tls_key_password`). TLS fields may be None
2121
and will be forwarded to uvicorn.run as provided.
2222
"""
@@ -31,7 +31,6 @@ def start_uvicorn(configuration: ServiceConfiguration) -> None:
3131
host=configuration.host,
3232
port=configuration.port,
3333
workers=configuration.workers,
34-
root_path=configuration.root_path,
3534
log_level=log_level,
3635
ssl_keyfile=configuration.tls_config.tls_key_path,
3736
ssl_certfile=configuration.tls_config.tls_certificate_path,

tests/unit/runners/test_uvicorn_runner.py

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@
1010

1111
def test_start_uvicorn(mocker: MockerFixture) -> None:
1212
"""Test the function to start Uvicorn server using de-facto default configuration."""
13-
configuration = ServiceConfiguration(
14-
host="localhost", port=8080, workers=1
15-
) # pyright: ignore[reportCallIssue]
13+
configuration = ServiceConfiguration(host="localhost", port=8080, workers=1) # pyright: ignore[reportCallIssue]
1614

1715
# don't start real Uvicorn server
1816
mocked_run = mocker.patch("uvicorn.run")
@@ -22,7 +20,6 @@ def test_start_uvicorn(mocker: MockerFixture) -> None:
2220
host="localhost",
2321
port=8080,
2422
workers=1,
25-
root_path="",
2623
log_level=20,
2724
ssl_certfile=None,
2825
ssl_keyfile=None,
@@ -34,9 +31,7 @@ def test_start_uvicorn(mocker: MockerFixture) -> None:
3431

3532
def test_start_uvicorn_different_host_port(mocker: MockerFixture) -> None:
3633
"""Test the function to start Uvicorn server using custom configuration."""
37-
configuration = ServiceConfiguration(
38-
host="x.y.com", port=1234, workers=10
39-
) # pyright: ignore[reportCallIssue]
34+
configuration = ServiceConfiguration(host="x.y.com", port=1234, workers=10) # pyright: ignore[reportCallIssue]
4035

4136
# don't start real Uvicorn server
4237
mocked_run = mocker.patch("uvicorn.run")
@@ -46,7 +41,6 @@ def test_start_uvicorn_different_host_port(mocker: MockerFixture) -> None:
4641
host="x.y.com",
4742
port=1234,
4843
workers=10,
49-
root_path="",
5044
log_level=20,
5145
ssl_certfile=None,
5246
ssl_keyfile=None,
@@ -71,7 +65,6 @@ def test_start_uvicorn_empty_tls_configuration(mocker: MockerFixture) -> None:
7165
host="x.y.com",
7266
port=1234,
7367
workers=10,
74-
root_path="",
7568
log_level=20,
7669
ssl_certfile=None,
7770
ssl_keyfile=None,
@@ -100,7 +93,6 @@ def test_start_uvicorn_tls_configuration(mocker: MockerFixture) -> None:
10093
host="x.y.com",
10194
port=1234,
10295
workers=10,
103-
root_path="",
10496
log_level=20,
10597
ssl_certfile=Path("tests/configuration/server.crt"),
10698
ssl_keyfile=Path("tests/configuration/server.key"),
@@ -111,7 +103,7 @@ def test_start_uvicorn_tls_configuration(mocker: MockerFixture) -> None:
111103

112104

113105
def test_start_uvicorn_with_root_path(mocker: MockerFixture) -> None:
114-
"""Test the function to start Uvicorn server with a custom root path."""
106+
"""Test that root_path is not passed to uvicorn (it belongs on the FastAPI constructor)."""
115107
configuration = ServiceConfiguration(
116108
host="localhost", port=8080, workers=1, root_path="/api/lightspeed"
117109
) # pyright: ignore[reportCallIssue]
@@ -124,7 +116,6 @@ def test_start_uvicorn_with_root_path(mocker: MockerFixture) -> None:
124116
host="localhost",
125117
port=8080,
126118
workers=1,
127-
root_path="/api/lightspeed",
128119
log_level=20,
129120
ssl_certfile=None,
130121
ssl_keyfile=None,

0 commit comments

Comments
 (0)