Skip to content

Commit e17d91c

Browse files
committed
Added simple types for response_model
1 parent d2eb92d commit e17d91c

File tree

3 files changed

+91
-2
lines changed

3 files changed

+91
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ FastOpenAPI follows the [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
1111
- Class-level cache for model schemas
1212
- `response_errors` for routers
1313
- `error_handler` for standard error responses
14+
- Some python types as response_model (`int`, `float`, `bool`, `str`)
1415

1516
## [0.4.0] - 2025-03-20
1617

fastopenapi/base_router.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,13 +271,21 @@ def _build_responses(self, meta: dict, definitions: dict, status_code: str) -> d
271271
responses[status_code]["content"] = {
272272
"application/json": {"schema": array_schema}
273273
}
274+
else:
275+
raise Exception("Incorrect response_model")
274276
elif isinstance(response_model, type) and issubclass(
275277
response_model, BaseModel
276278
):
277279
resp_model_schema = self._get_model_schema(response_model, definitions)
278280
responses[status_code]["content"] = {
279281
"application/json": {"schema": resp_model_schema}
280282
}
283+
elif response_model in PYTHON_TYPE_MAPPING:
284+
responses[status_code]["content"] = {
285+
"application/json": {
286+
"schema": {"type": PYTHON_TYPE_MAPPING[response_model]}
287+
}
288+
}
281289
else:
282290
raise Exception("Incorrect response_model")
283291
return responses

tests/test_base_router.py

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ class NestedModel(BaseModel):
2424
extra: str | None = None
2525

2626

27+
class NestedListModel(BaseModel):
28+
data: list[TestModel]
29+
extra: str | None = None
30+
31+
2732
class TestBaseRouter:
2833

2934
def setup_method(self):
@@ -246,16 +251,65 @@ def create_user(user: TestModel):
246251
assert ref == "#/components/schemas/TestModel"
247252
assert "TestModel" in schema["components"]["schemas"]
248253

254+
def test_generate_openapi_with_response_error(self):
255+
# Test OpenAPI generation with response error
256+
257+
@self.router.post("/users", response_errors=[400, 404, 500], response_model=int)
258+
def create_user(user: TestModel):
259+
return 1
260+
261+
schema = self.router.generate_openapi()
262+
263+
# Check response
264+
response = schema["paths"]["/users"]["post"]["responses"]["200"]
265+
assert "content" in response
266+
assert "application/json" in response["content"]
267+
268+
responses = schema["paths"]["/users"]["post"]["responses"]
269+
assert "200" in responses
270+
assert "400" in responses
271+
assert "404" in responses
272+
assert "500" in responses
273+
274+
assert "ErrorSchema" in schema["components"]["schemas"]
275+
249276
def test_generate_openapi_with_incorrect_response_model(self):
250277
# Test OpenAPI generation with incorrect response model
251278

252-
@self.router.post("/users", response_model=int)
279+
@self.router.post("/users", response_model=tuple)
253280
def create_user(user: TestModel):
254-
return 1
281+
return (1, 2)
255282

256283
with pytest.raises(Exception, match="Incorrect response_model"):
257284
self.router.generate_openapi()
258285

286+
def test_generate_openapi_with_incorrect_list_response_model(self):
287+
# Test OpenAPI generation with incorrect response model
288+
289+
@self.router.post("/users", response_model=list[tuple])
290+
def create_user(user: TestModel):
291+
return [(1, 2)]
292+
293+
with pytest.raises(Exception, match="Incorrect response_model"):
294+
self.router.generate_openapi()
295+
296+
def test_generate_openapi_with_simple_type_as_response_model(self):
297+
# Test OpenAPI generation with python type as response model
298+
299+
@self.router.post("/users", response_model=int)
300+
def create_user(user: TestModel):
301+
return 1
302+
303+
schema = self.router.generate_openapi()
304+
305+
# Check response
306+
response = schema["paths"]["/users"]["post"]["responses"]["200"]
307+
assert "content" in response
308+
assert "application/json" in response["content"]
309+
310+
resp_type = response["content"]["application/json"]["schema"]["type"]
311+
assert "integer" == resp_type
312+
259313
def test_generate_openapi_with_response_model(self):
260314
# Test OpenAPI generation with response model
261315

@@ -276,6 +330,32 @@ def create_user(user: TestModel):
276330
assert ref == "#/components/schemas/ResponseModel"
277331
assert "ResponseModel" in schema["components"]["schemas"]
278332

333+
def test_generate_openapi_with_nested_list_response_model(self):
334+
# Test OpenAPI generation with response model with nested model list
335+
336+
@self.router.post("/users", response_model=NestedListModel)
337+
def create_user(user: TestModel):
338+
pass
339+
340+
schema = self.router.generate_openapi()
341+
342+
# Check response
343+
response = schema["paths"]["/users"]["post"]["responses"]["200"]
344+
assert "content" in response
345+
assert "application/json" in response["content"]
346+
assert "$ref" in response["content"]["application/json"]["schema"]
347+
348+
# Check that response model schema is in components
349+
ref = response["content"]["application/json"]["schema"]["$ref"]
350+
schemas = schema["components"]["schemas"]
351+
assert ref == "#/components/schemas/NestedListModel"
352+
assert "NestedListModel" in schemas
353+
assert "TestModel" in schemas
354+
355+
# Check that TestModel inside NestedModel
356+
ref = schemas["NestedListModel"]["properties"]["data"]["items"]["$ref"]
357+
assert ref == "#/components/schemas/TestModel"
358+
279359
def test_generate_openapi_with_list_response(self):
280360
# Test OpenAPI generation with List response model
281361

0 commit comments

Comments
 (0)