Skip to content

Commit 3021cb5

Browse files
authored
Fix servers and global root_path (#235)
1 parent 37af808 commit 3021cb5

5 files changed

Lines changed: 122 additions & 2 deletions

File tree

docs/en/docs/release-notes.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,14 @@ hide:
77

88
## 0.19.1
99

10+
### Changed
11+
12+
- Root path for auto detection behind reverse proxies.
13+
1014
### Fixed
1115

1216
- Typo in the error for the security.
17+
- Servers for `openapi` were not being detected automatically.
1318

1419
## 0.19.0
1520

lilya/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.19.0"
1+
__version__ = "0.19.1"

lilya/apps.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,9 @@ async def hello(self):
465465
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
466466
scope["app"] = self
467467
with _monkay.with_settings(self.settings), _monkay.with_instance(self):
468+
if self.root_path:
469+
scope["root_path"] = self.root_path
470+
468471
if self.middleware_stack is None:
469472
self.middleware_stack = self.build_middleware_stack()
470473
await self.middleware_stack(scope, receive, send)
@@ -957,6 +960,25 @@ async def populate_g(connection: Connection):
957960
"""
958961
),
959962
] = False,
963+
root_path: Annotated[
964+
str | None,
965+
Doc(
966+
"""
967+
A path prefix that is handled by a proxy not seen in the
968+
application but seen by external libraries.
969+
970+
This affects the tools like the OpenAPI documentation.
971+
972+
**Example**
973+
974+
```python
975+
from lilya.apps import Lilya
976+
977+
app = Lilya(root_path="/api/v3")
978+
```
979+
"""
980+
),
981+
] = None,
960982
) -> None:
961983
self.populate_global_context = populate_global_context
962984
self.settings_module: Settings | None = None
@@ -1008,6 +1030,8 @@ async def populate_g(connection: Connection):
10081030
self.enable_intercept_global_exceptions = self.load_settings_value(
10091031
"enable_intercept_global_exceptions", enable_intercept_global_exceptions
10101032
)
1033+
self.root_path = self.load_settings_value("root_path", root_path)
1034+
10111035
if self.router_class is not None:
10121036
self.router = self.router_class(
10131037
routes=routes,

lilya/conf/global_settings.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,6 @@ class Settings(Internal):
286286
"""
287287
),
288288
] = True
289-
290289
default_route_pattern: Annotated[
291290
str,
292291
Doc(
@@ -468,6 +467,26 @@ async def create_user(request: Request):
468467
"""
469468
),
470469
] = False
470+
root_path_in_servers: Annotated[
471+
bool,
472+
Doc(
473+
"""
474+
Boolean flag use to disable the automatic URL generation in the `servers` field
475+
in the OpenAPI documentation.
476+
"""
477+
),
478+
] = True
479+
root_path: Annotated[
480+
str | None,
481+
Doc(
482+
"""
483+
A path prefix that is handled by a proxy not seen in the
484+
application but seen by external libraries.
485+
486+
This affects the tools like the OpenAPI documentation.
487+
"""
488+
),
489+
] = ""
471490

472491
@property
473492
def routes(self) -> list[Any]:

tests/openapi/test_servers.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
from typing import Any
2+
3+
from lilya.apps import Lilya
4+
from lilya.contrib.openapi.config import OpenAPIConfig
5+
from lilya.contrib.openapi.decorator import openapi
6+
from lilya.routing import Path
7+
from lilya.testclient import TestClient
8+
9+
10+
class CustomOpenAPIConfig(OpenAPIConfig):
11+
servers: Any = [
12+
{"url": "/", "description": "Default server"},
13+
{
14+
"url": "http://staging.esmerald.dev",
15+
"description": "Staging of Esmerald",
16+
},
17+
{"url": "https://esmerald.dev"},
18+
]
19+
20+
21+
@openapi(summary="Bar", description="", operation_id="bar_bar_get")
22+
async def bar() -> dict[str, str]:
23+
return {"hello": "world"}
24+
25+
26+
app = Lilya(
27+
routes=[Path("/bar", handler=bar)],
28+
enable_openapi=True,
29+
openapi_config=CustomOpenAPIConfig(),
30+
)
31+
32+
33+
client = TestClient(app)
34+
35+
36+
def test_application(test_client_factory):
37+
response = client.get("/bar")
38+
assert response.status_code == 200, response.json()
39+
40+
41+
def test_openapi_schema(test_client_factory):
42+
response = client.get("/openapi.json")
43+
44+
assert response.status_code == 200, response.text
45+
46+
assert response.json() == {
47+
"openapi": "3.1.0",
48+
"info": {
49+
"title": "Lilya",
50+
"version": client.app.version,
51+
"summary": "Lilya application",
52+
"description": "Yet another framework/toolkit that delivers.",
53+
"contact": {"name": "Lilya", "url": "https://lilya.dev", "email": "admin@myapp.com"},
54+
},
55+
"paths": {
56+
"/bar": {
57+
"get": {
58+
"operationId": "bar_bar_get",
59+
"summary": "Bar",
60+
"description": "",
61+
"parameters": [],
62+
"responses": {"200": {"description": "Successful response"}},
63+
}
64+
}
65+
},
66+
"components": {"schemas": {}, "securitySchemes": {}},
67+
"servers": [
68+
{"url": "/", "description": "Default server"},
69+
{"url": "http://staging.esmerald.dev", "description": "Staging of Esmerald"},
70+
{"url": "https://esmerald.dev"},
71+
],
72+
}

0 commit comments

Comments
 (0)