Skip to content

Commit 92d2a9b

Browse files
committed
Fixed docs, added custom security_scheme, increased tracerite version
1 parent f27fd9b commit 92d2a9b

6 files changed

Lines changed: 72 additions & 24 deletions

File tree

docs/api_reference/errors.md

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -194,13 +194,7 @@ Content-Type: application/json
194194
"type": "validation_error",
195195
"message": "Validation error",
196196
"status": 422,
197-
"details": [
198-
{
199-
"loc": ["body", "email"],
200-
"msg": "value is not a valid email address",
201-
"type": "value_error.email"
202-
}
203-
]
197+
"details": "Value is not a valid email address"
204198
}
205199
}
206200
```
@@ -606,9 +600,7 @@ All errors follow this structure:
606600
"type": "error_type_identifier",
607601
"message": "Human-readable error message",
608602
"status": 400,
609-
"details": {
610-
// Optional additional details
611-
}
603+
"details": "Optional additional details (string, included only when provided)"
612604
}
613605
}
614606
```

docs/frameworks/django.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ from fastopenapi import Path
186186
def get_user(user_id: int = Path(..., description="User ID")):
187187
return {"user_id": user_id}
188188

189-
# Django URL: /users/<int:user_id>
189+
# Django URL: /users/<user_id>
190190
```
191191

192192
## Request Data

docs/guide/error_handling.md

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,15 +99,9 @@ All errors return a standardized JSON format:
9999
{
100100
"error": {
101101
"type": "validation_error",
102-
"message": "Validation error",
102+
"message": "Error parsing parameter 'email'",
103103
"status": 422,
104-
"details": [
105-
{
106-
"loc": ["body", "email"],
107-
"msg": "Invalid email format",
108-
"type": "value_error"
109-
}
110-
]
104+
"details": "Value is not a valid email address"
111105
}
112106
}
113107
```

fastopenapi/core/router.py

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ def __init__(
3737
title: str = "My App",
3838
version: str = "0.1.0",
3939
description: str = "API documentation",
40-
security_scheme: SecuritySchemeType | None = SecuritySchemeType.BEARER_JWT,
40+
security_scheme: (
41+
SecuritySchemeType | dict | None
42+
) = SecuritySchemeType.BEARER_JWT,
4143
):
4244
self.app = app
4345
self.docs_url = docs_url
@@ -53,8 +55,25 @@ def __init__(
5355
self._global_security = []
5456

5557
if security_scheme:
56-
scheme_name = SECURITY_SCHEME_NAMES[security_scheme]
57-
self._security_schemes = {scheme_name: SECURITY_SCHEMES[security_scheme]}
58+
if isinstance(security_scheme, dict):
59+
scheme_type = security_scheme.get("type", "")
60+
http_scheme = security_scheme.get("scheme", "")
61+
if scheme_type == "http" and http_scheme == "bearer":
62+
name = "BearerAuth"
63+
elif scheme_type == "http" and http_scheme == "basic":
64+
name = "BasicAuth"
65+
elif scheme_type == "apiKey":
66+
name = "ApiKeyAuth"
67+
elif scheme_type == "oauth2":
68+
name = "OAuth2"
69+
else:
70+
name = "CustomAuth"
71+
self._security_schemes = {name: security_scheme}
72+
else:
73+
scheme_name = SECURITY_SCHEME_NAMES[security_scheme]
74+
self._security_schemes = {
75+
scheme_name: SECURITY_SCHEMES[security_scheme]
76+
}
5877

5978
# Register documentation endpoints if app is provided
6079
if self.app is not None and all([docs_url, redoc_url, openapi_url]):

pyproject.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,5 +69,4 @@ trio = "^0.29.0"
6969
pytest-asyncio = "^0.25.3"
7070
coverage = "^7.6.12"
7171
mkdocs-material = "^9.6.11"
72-
# Temporary fix https://github.com/sanic-org/tracerite/issues/20
73-
tracerite = "1.1.1"
72+
tracerite = "^1.1.3"

tests/core/test_base_router.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,50 @@ def test_include_router_merges_security_schemes_both(self):
129129
assert "BearerAuth" in parent._security_schemes
130130
assert "ApiKey" in parent._security_schemes
131131

132+
def test_security_scheme_dict_bearer(self):
133+
"""Test security_scheme as dict with bearer type"""
134+
router = BaseRouter(
135+
security_scheme={
136+
"type": "http",
137+
"scheme": "bearer",
138+
"bearerFormat": "JWT",
139+
"description": "Custom bearer",
140+
}
141+
)
142+
assert router._security_schemes is not None
143+
assert "BearerAuth" in router._security_schemes
144+
assert router._security_schemes["BearerAuth"]["description"] == "Custom bearer"
145+
146+
def test_security_scheme_dict_oauth2(self):
147+
"""Test security_scheme as dict with oauth2 type"""
148+
router = BaseRouter(
149+
security_scheme={
150+
"type": "oauth2",
151+
"flows": {"password": {"tokenUrl": "/token", "scopes": {}}},
152+
}
153+
)
154+
assert "OAuth2" in router._security_schemes
155+
156+
def test_security_scheme_dict_apikey(self):
157+
"""Test security_scheme as dict with apiKey type"""
158+
router = BaseRouter(
159+
security_scheme={"type": "apiKey", "in": "header", "name": "X-My-Key"}
160+
)
161+
assert "ApiKeyAuth" in router._security_schemes
162+
assert router._security_schemes["ApiKeyAuth"]["name"] == "X-My-Key"
163+
164+
def test_security_scheme_dict_basic(self):
165+
"""Test security_scheme as dict with basic auth type"""
166+
router = BaseRouter(security_scheme={"type": "http", "scheme": "basic"})
167+
assert "BasicAuth" in router._security_schemes
168+
169+
def test_security_scheme_dict_custom(self):
170+
"""Test security_scheme as dict with unknown type"""
171+
router = BaseRouter(
172+
security_scheme={"type": "openIdConnect", "openIdConnectUrl": "/openid"}
173+
)
174+
assert "CustomAuth" in router._security_schemes
175+
132176
def test_include_router_merges_global_security(self):
133177
"""Test that include_router merges global security from sub-router"""
134178
parent = BaseRouter(security_scheme=None)

0 commit comments

Comments
 (0)