Skip to content

Commit 40b0508

Browse files
committed
Added security schemes merging
1 parent 403a746 commit 40b0508

2 files changed

Lines changed: 62 additions & 0 deletions

File tree

fastopenapi/core/router.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,17 @@ def include_router(self, other: "BaseRouter", prefix: str = ""):
7676
)
7777
self.add_route(path, route.method, route.endpoint)
7878

79+
# Merge security schemes
80+
if other._security_schemes:
81+
if self._security_schemes is None:
82+
self._security_schemes = {}
83+
self._security_schemes.update(other._security_schemes)
84+
85+
# Merge global security
86+
for sec in other._global_security:
87+
if sec not in self._global_security:
88+
self._global_security.append(sec)
89+
7990
def get_routes(self) -> list[RouteInfo]:
8091
"""Get all registered routes"""
8192
return self._routes

tests/core/test_base_router.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,57 @@ def test_endpoint():
101101
assert len(self.router._routes) == 2
102102
assert self.router._routes[1].path == "/other"
103103

104+
def test_include_router_merges_security_schemes(self):
105+
"""Test that include_router merges security schemes from sub-router"""
106+
other_router = BaseRouter(security_scheme=None)
107+
other_router._security_schemes = {"ApiKey": {"type": "apiKey", "in": "header"}}
108+
109+
# Parent has no security schemes
110+
parent = BaseRouter(security_scheme=None)
111+
assert parent._security_schemes is None
112+
113+
parent.include_router(other_router)
114+
assert parent._security_schemes == {
115+
"ApiKey": {"type": "apiKey", "in": "header"}
116+
}
117+
118+
def test_include_router_merges_security_schemes_both(self):
119+
"""Test merging when both routers have security schemes"""
120+
from fastopenapi.core.constants import SecuritySchemeType
121+
122+
parent = BaseRouter(security_scheme=SecuritySchemeType.BEARER_JWT)
123+
assert parent._security_schemes is not None
124+
125+
other = BaseRouter(security_scheme=None)
126+
other._security_schemes = {"ApiKey": {"type": "apiKey", "in": "header"}}
127+
128+
parent.include_router(other)
129+
assert "BearerAuth" in parent._security_schemes
130+
assert "ApiKey" in parent._security_schemes
131+
132+
def test_include_router_merges_global_security(self):
133+
"""Test that include_router merges global security from sub-router"""
134+
parent = BaseRouter(security_scheme=None)
135+
parent._global_security = [{"BearerJWT": []}]
136+
137+
other = BaseRouter(security_scheme=None)
138+
other._global_security = [{"ApiKey": []}, {"BearerJWT": []}]
139+
140+
parent.include_router(other)
141+
# Should have both, no duplicates
142+
assert {"BearerJWT": []} in parent._global_security
143+
assert {"ApiKey": []} in parent._global_security
144+
assert len(parent._global_security) == 2
145+
146+
def test_include_router_no_security_no_change(self):
147+
"""Test include_router with sub-router without security"""
148+
parent = BaseRouter(security_scheme=None)
149+
other = BaseRouter(security_scheme=None)
150+
151+
parent.include_router(other)
152+
assert parent._security_schemes is None
153+
assert parent._global_security == []
154+
104155
def test_http_method_decorators(self):
105156
# Test all HTTP method decorators
106157

0 commit comments

Comments
 (0)