Skip to content

Commit 057abb8

Browse files
committed
Added tests for openapi responses.
Signed-off-by: Pavel Kirilin <win10@list.ru>
1 parent 673ce84 commit 057abb8

2 files changed

Lines changed: 100 additions & 6 deletions

File tree

aiohttp_deps/swagger.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ def _insert_in_params(data: Dict[str, Any]) -> None:
9898
params[(data["name"], data["in"])] = data
9999
return
100100
element["required"] = element.get("required") or data.get("required")
101-
element["allowEmptyValue"] = element.get("allowEmptyValue") and data.get(
102-
"allowEmptyValue",
101+
element["allowEmptyValue"] = bool(element.get("allowEmptyValue")) and bool(
102+
data.get("allowEmptyValue"),
103103
)
104104
params[(data["name"], data["in"])] = element
105105

@@ -317,10 +317,12 @@ def decorator(func: _T) -> _T:
317317
openapi = getattr(func, "__extra_openapi__", {})
318318
adapter: "pydantic.TypeAdapter[Any]" = pydantic.TypeAdapter(model)
319319
responses = openapi.get("responses", {})
320-
responses[status] = {
321-
"description": description,
322-
"content": {content_type: {"schema": adapter.json_schema()}},
323-
}
320+
status_response = responses.get(status, {})
321+
if not status_response:
322+
status_response["description"] = description
323+
status_response["content"] = status_response.get("content", {})
324+
status_response["content"][content_type] = {"schema": adapter.json_schema()}
325+
responses[status] = status_response
324326
openapi["responses"] = responses
325327
func.__extra_openapi__ = openapi # type: ignore
326328
return func

tests/test_swagger.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
extra_openapi,
1717
setup_swagger,
1818
)
19+
from aiohttp_deps.swagger import openapi_response
1920
from tests.conftest import ClientGenerator
2021

2122

@@ -470,3 +471,94 @@ async def post():
470471

471472
handler_info = resp_json["paths"]["/a"]["post"]
472473
assert handler_info["post_info"] == "wow"
474+
475+
476+
@pytest.mark.anyio
477+
async def test_merge_headers(
478+
my_app: web.Application,
479+
aiohttp_client: ClientGenerator,
480+
) -> None:
481+
OPENAPI_URL = "/my_api_def.json"
482+
my_app.on_startup.append(setup_swagger(schema_url=OPENAPI_URL))
483+
484+
async def my_handler(
485+
my_var: Optional[str] = Depends(Header(alias="head")),
486+
my_var2: Optional[str] = Depends(Header(alias="head")),
487+
my_var3: str = Depends(Header(alias="head")),
488+
):
489+
"""Nothing."""
490+
491+
my_app.router.add_get("/a", my_handler)
492+
493+
client = await aiohttp_client(my_app)
494+
resp = await client.get(OPENAPI_URL)
495+
assert resp.status == 200
496+
resp_json = await resp.json()
497+
params = resp_json["paths"]["/a"]["get"]["parameters"]
498+
print(params)
499+
assert len(params) == 1
500+
assert params[0]["name"] == "Head"
501+
assert params[0]["required"]
502+
assert not params[0]["allowEmptyValue"]
503+
504+
505+
@pytest.mark.anyio
506+
async def test_custom_responses(
507+
my_app: web.Application,
508+
aiohttp_client: ClientGenerator,
509+
) -> None:
510+
OPENAPI_URL = "/my_api_def.json"
511+
my_app.on_startup.append(setup_swagger(schema_url=OPENAPI_URL))
512+
513+
class RespModel(BaseModel):
514+
name: str
515+
age: int
516+
517+
class UnauthModel(BaseModel):
518+
why: str
519+
520+
@openapi_response(200, RespModel)
521+
@openapi_response(401, UnauthModel)
522+
async def my_handler():
523+
"""Nothing."""
524+
525+
my_app.router.add_get("/a", my_handler)
526+
527+
client = await aiohttp_client(my_app)
528+
resp = await client.get(OPENAPI_URL)
529+
resp_json = await resp.json()
530+
route_info = resp_json["paths"]["/a"]["get"]
531+
assert "401" in route_info["responses"]
532+
assert "200" in route_info["responses"]
533+
assert "schema" in route_info["responses"]["200"]["content"]["application/json"]
534+
assert "schema" in route_info["responses"]["401"]["content"]["application/json"]
535+
536+
537+
@pytest.mark.anyio
538+
async def test_custom_responses_multi_content_type(
539+
my_app: web.Application,
540+
aiohttp_client: ClientGenerator,
541+
) -> None:
542+
OPENAPI_URL = "/my_api_def.json"
543+
my_app.on_startup.append(setup_swagger(schema_url=OPENAPI_URL))
544+
545+
class First(BaseModel):
546+
name: str
547+
548+
class Second(BaseModel):
549+
age: int
550+
551+
@openapi_response(200, First, content_type="application/json")
552+
@openapi_response(200, Second, content_type="application/xml")
553+
async def my_handler():
554+
"""Nothing."""
555+
556+
my_app.router.add_get("/a", my_handler)
557+
558+
client = await aiohttp_client(my_app)
559+
resp = await client.get(OPENAPI_URL)
560+
resp_json = await resp.json()
561+
route_info = resp_json["paths"]["/a"]["get"]
562+
assert "200" in route_info["responses"]
563+
assert "application/json" in route_info["responses"]["200"]["content"]
564+
assert "application/xml" in route_info["responses"]["200"]["content"]

0 commit comments

Comments
 (0)