From 98f20c2b23a154fab00b9350fdf2d367d77e8bec Mon Sep 17 00:00:00 2001 From: Yurii Motov Date: Wed, 5 Nov 2025 21:25:39 +0100 Subject: [PATCH] Add tests for Body field aliases --- tests/test_aliases/test_body_field_aliases.py | 702 ++++++++++++++++++ .../test_body_field_aliases_pd_v1.py | 166 +++++ 2 files changed, 868 insertions(+) create mode 100644 tests/test_aliases/test_body_field_aliases.py create mode 100644 tests/test_aliases/test_body_field_aliases_pd_v1.py diff --git a/tests/test_aliases/test_body_field_aliases.py b/tests/test_aliases/test_body_field_aliases.py new file mode 100644 index 000000000..0fbdb6775 --- /dev/null +++ b/tests/test_aliases/test_body_field_aliases.py @@ -0,0 +1,702 @@ +from typing import List, Optional + +import pytest +from fastapi import Body, FastAPI +from fastapi.testclient import TestClient + +from ..utils import needs_pydanticv2 + +pytestmark = needs_pydanticv2 + + +app = FastAPI() + +# ===================================================================================== +# Body(alias=...) +# Current situation: Works, but schema is wrong + +# ------------------------------ +# required field + + +@app.post("/required-field-alias", operation_id="required_field_alias") +async def required_field_alias( + param: str = Body(alias="param_alias", embed=True), +): + return {"param": param} + + +def test_required_field_alias_(): + client = TestClient(app) + resp = client.post("/required-field-alias", json={"param": "123"}) + assert resp.status_code == 422 + detail = resp.json()["detail"] + assert detail[0]["msg"] == "Field required" + assert "param_alias" in detail[0]["loc"] + + +def test_required_field_alias_by_alias(): + client = TestClient(app) + resp = client.post("/required-field-alias", json={"param_alias": "123"}) + assert resp.status_code == 200 + assert resp.json() == {"param": "123"} + + +@pytest.mark.xfail(raises=AssertionError, strict=False) +def test_required_field_alias_schema(): + openapi = app.openapi() + body_schema = openapi["components"]["schemas"]["Body_required_field_alias"] + assert body_schema["properties"] == { + "param_alias": {"type": "string", "title": "Param Alias"} + } + # Currently fails due to issue with aliases: + # AssertionError: assert + # {'param': {'type': 'string', 'title': 'Param'}} == + # {'param_alias': {'type': 'string', 'title': 'Param Alias'}} + + +# ------------------------------ +# optional field + + +@app.post("/optional-field-alias", operation_id="optional_field_alias") +async def optional_field_alias( + param: Optional[str] = Body(None, alias="param_alias", embed=True), +): + return {"param": param} + + +def test_optional_field_alias_by_name(): + client = TestClient(app) + resp = client.post("/optional-field-alias", json={"param": "123"}) + assert resp.status_code == 200 + assert resp.json() == {"param": None} + + +def test_optional_field_alias_by_alias(): + client = TestClient(app) + resp = client.post("/optional-field-alias", json={"param_alias": "123"}) + assert resp.status_code == 200 + assert resp.json() == {"param": "123"} + + +@pytest.mark.xfail(raises=AssertionError, strict=False) +def test_optional_field_alias_schema(): + openapi = app.openapi() + body_schema = openapi["components"]["schemas"]["Body_optional_field_alias"] + assert body_schema["properties"] == { + "param_alias": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Param Alias", + }, + } + # Currently fails due to issue with aliases: + # AssertionError: assert + # {'param': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'title': 'Param'}} == + # {'param_alias': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'title': 'Param Alias'}} + + +# ------------------------------ +# list field + + +@app.post("/list-field-alias", operation_id="list_field_alias") +async def list_field_alias(param: List[str] = Body(alias="param_alias", embed=True)): + return {"param": param} + + +def test_list_field_alias_by_name(): + client = TestClient(app) + resp = client.post("/list-field-alias", json={"param": ["123", "456"]}) + assert resp.status_code == 422 + detail = resp.json()["detail"] + assert detail[0]["msg"] == "Field required" + assert "param_alias" in detail[0]["loc"] + + +def test_list_field_alias_by_alias(): + client = TestClient(app) + resp = client.post("/list-field-alias", json={"param_alias": ["123", "456"]}) + assert resp.status_code == 200 + assert resp.json() == {"param": ["123", "456"]} + + +@pytest.mark.xfail(raises=AssertionError, strict=False) +def test_list_field_alias_schema(): + openapi = app.openapi() + body_schema = openapi["components"]["schemas"]["Body_list_field_alias"] + assert body_schema["properties"] == { + "param_alias": { + "items": {"type": "string"}, + "type": "array", + "title": "Param Alias", + } + } + # Currently fails due to issue with aliases: + # AssertionError: assert + # {'param': {'items': {'type': 'string'}, 'type': 'array', 'title': 'Param'}} == + # {'param_alias': {'items': {'type': 'string'}, 'type': 'array', 'title': 'Param Alias'}} + + +# ------------------------------ +# optional list field + + +@app.post("/optional-list-field-alias", operation_id="optional_list_field_alias") +async def optional_list_field_alias( + param: Optional[List[str]] = Body(None, alias="param_alias", embed=True), +): + return {"param": param} + + +def test_optional_list_field_alias_by_name(): + client = TestClient(app) + resp = client.post("/optional-list-field-alias", json={"param": ["123", "456"]}) + assert resp.status_code == 200 + assert resp.json() == {"param": None} + + +def test_optional_list_field_alias_by_alias(): + client = TestClient(app) + resp = client.post( + "/optional-list-field-alias", json={"param_alias": ["123", "456"]} + ) + assert resp.status_code == 200 + assert resp.json() == {"param": ["123", "456"]} + + +@pytest.mark.xfail(raises=AssertionError, strict=False) +def test_optional_list_field_alias_schema(): + openapi = app.openapi() + body_schema = openapi["components"]["schemas"]["Body_optional_list_field_alias"] + assert body_schema["properties"] == { + "param_alias": { + "anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], + "title": "Param Alias", + }, + } + # Currently fails due to issue with aliases: + # AssertionError: assert + # {'param': {'anyOf': [{'items': {'type': 'string'}, 'type': 'array'}, {'type': 'null'}], 'title': 'Param'}} == + # {'param_alias': {'anyOf': [{'items': {'type': 'string'}, 'type': 'array'}, {'type': 'null'}], 'title': 'Param Alias'}} + + +# ===================================================================================== +# Body(validation_alias=...) +# Current situation: schema is correct, but doesn't work (parameter name is used) + + +# ------------------------------ +# required field + + +@app.post( + "/required-field-validation-alias", operation_id="required_field_validation_alias" +) +async def required_field_validation_alias( + param: str = Body(validation_alias="param_val_alias", embed=True), +): + return {"param": param} + + +@pytest.mark.xfail(raises=AssertionError, strict=False) +def test_required_field_validation_alias_by_name(): + client = TestClient(app) + resp = client.post("/required-field-validation-alias", json={"param": "123"}) + assert resp.status_code == 422 + # Currently fails due to issue with aliases: + # AssertionError: assert 200 == 422 + + # Uncomment when the assertion above passes: + # detail = resp.json()["detail"] + # assert detail[0]["msg"] == "Field required" + # assert "param_val_alias" in detail[0]["loc"] + + +@pytest.mark.xfail(raises=AssertionError, strict=False) +def test_required_field_validation_alias_by_alias(): + client = TestClient(app) + resp = client.post( + "/required-field-validation-alias", json={"param_val_alias": "123"} + ) + assert resp.status_code == 200 + # Currently fails due to issue with aliases: + # AssertionError: assert 422 == 200 + + # Uncomment when the assertion above passes: + # assert resp.json() == {"param": "123"} + + +def test_required_field_validation_alias_schema(): + openapi = app.openapi() + body_schema = openapi["components"]["schemas"][ + "Body_required_field_validation_alias" + ] + assert body_schema["properties"] == { + "param_val_alias": {"title": "Param Val Alias", "type": "string"}, + } + + +# ------------------------------ +# optional field + + +@app.post( + "/optional-field-validation-alias", operation_id="optional_field_validation_alias" +) +async def optional_field_validation_alias( + param: Optional[str] = Body(None, validation_alias="param_val_alias", embed=True), +): + return {"param": param} + + +@pytest.mark.xfail(raises=AssertionError, strict=False) +def test_optional_field_validation_alias_by_name(): + client = TestClient(app) + resp = client.post("/optional-field-validation-alias", json={"param": "123"}) + assert resp.json() == {"param": None} + # Currently fails due to issue with aliases: + # AssertionError: assert {'param': '123'} == {'param': None} + + +@pytest.mark.xfail(raises=AssertionError, strict=False) +def test_optional_field_validation_alias_by_alias(): + client = TestClient(app) + resp = client.post( + "/optional-field-validation-alias", json={"param_val_alias": "123"} + ) + assert resp.status_code == 200 + assert resp.json() == {"param": "123"} + # Currently fails due to issue with aliases: + # AssertionError: assert {'param': None} == {'param': '123'} + + +def test_optional_field_validation_alias_schema(): + openapi = app.openapi() + body_schema = openapi["components"]["schemas"][ + "Body_optional_field_validation_alias" + ] + assert body_schema["properties"] == { + "param_val_alias": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Param Val Alias", + }, + } + + +# ------------------------------ +# list field + + +@app.post("/list-field-validation-alias", operation_id="list_field_validation_alias") +async def list_field_validation_alias( + param: List[str] = Body(validation_alias="param_val_alias", embed=True), +): + return {"param": param} + + +@pytest.mark.xfail(raises=AssertionError, strict=False) +def test_list_field_validation_alias_by_name(): + client = TestClient(app) + resp = client.post("/list-field-validation-alias", json={"param": ["123", "456"]}) + assert resp.status_code == 422 + # Currently fails due to issue with aliases: + # AssertionError: assert 200 == 422 + + # Uncomment when the assertion above passes: + # detail = resp.json()["detail"] + # assert detail[0]["msg"] == "Field required" + # assert "param_val_alias" in detail[0]["loc"] + + +@pytest.mark.xfail(raises=AssertionError, strict=False) +def test_list_field_validation_alias_by_alias(): + client = TestClient(app) + resp = client.post( + "/list-field-validation-alias", json={"param_val_alias": ["123", "456"]} + ) + assert resp.status_code == 200 + # Currently fails due to issue with aliases: + # AssertionError: assert 422 == 200 + + # Uncomment when the assertion above passes: + # assert resp.json() == {"param": ["123", "456"]} + + +def test_list_field_validation_alias_schema(): + openapi = app.openapi() + body_schema = openapi["components"]["schemas"]["Body_list_field_validation_alias"] + assert body_schema["properties"] == { + "param_val_alias": { + "items": {"type": "string"}, + "title": "Param Val Alias", + "type": "array", + }, + } + + +# ------------------------------ +# optional list field + + +@app.post( + "/optional-list-field-validation-alias", + operation_id="optional_list_field_validation_alias", +) +async def optional_list_field_validation_alias( + param: Optional[List[str]] = Body( + None, validation_alias="param_val_alias", embed=True + ), +): + return {"param": param} + + +@pytest.mark.xfail(raises=AssertionError, strict=False) +def test_optional_list_field_validation_alias_by_name(): + client = TestClient(app) + resp = client.post( + "/optional-list-field-validation-alias", json={"param": ["123", "456"]} + ) + assert resp.status_code == 200 + assert resp.json() == {"param": None} + # Currently fails due to issue with aliases: + # AssertionError: assert {'param': ['123', '456']} == {'param': None} + + +@pytest.mark.xfail(raises=AssertionError, strict=False) +def test_optional_list_field_validation_alias_by_alias(): + client = TestClient(app) + resp = client.post( + "/optional-list-field-validation-alias", + json={"param_val_alias": ["123", "456"]}, + ) + assert resp.status_code == 200 + assert resp.json() == {"param": ["123", "456"]} + # Currently fails due to issue with aliases: + # AssertionError: assert {'param': None} == {'param': ['123', '456']} + + +def test_optional_list_field_validation_alias_schema(): + openapi = app.openapi() + body_schema = openapi["components"]["schemas"][ + "Body_optional_list_field_validation_alias" + ] + assert body_schema["properties"] == { + "param_val_alias": { + "anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], + "title": "Param Val Alias", + }, + } + + +# ===================================================================================== +# Body(alias=..., validation_alias=...) +# Current situation: Schema is correct (validation_alias), but doesn't work (alias is used) + +# ------------------------------ +# required field + + +@app.post( + "/required-field-alias-and-validation-alias", + operation_id="required_field_alias_and_validation_alias", +) +async def required_field_alias_and_validation_alias( + param: str = Body( + alias="param_alias", validation_alias="param_val_alias", embed=True + ), +): + return {"param": param} + + +@pytest.mark.xfail(raises=AssertionError, strict=False) +def test_required_field_alias_and_validation_alias_by_name(): + client = TestClient(app) + resp = client.post( + "/required-field-alias-and-validation-alias", json={"param": "123"} + ) + assert resp.status_code == 422 + detail = resp.json()["detail"] + assert detail[0]["msg"] == "Field required" + assert "param_val_alias" in detail[0]["loc"] + # Currently fails due to issue with aliases: + # AssertionError: assert 'param_val_alias' in ['body', 'param_alias'] + + +@pytest.mark.xfail(raises=AssertionError, strict=False) +def test_required_field_alias_and_validation_alias_by_alias(): + client = TestClient(app) + resp = client.post( + "/required-field-alias-and-validation-alias", json={"param_alias": "123"} + ) + assert resp.status_code == 422 + # Currently fails due to issue with aliases: + # AssertionError: assert 200 == 422 + + # Uncomment when the assertion above passes: + # detail = resp.json()["detail"] + # assert detail[0]["msg"] == "Field required" + # assert "param_val_alias" in detail[0]["loc"] + + +@pytest.mark.xfail(raises=AssertionError, strict=False) +def test_required_field_alias_and_validation_alias_by_validation_alias(): + client = TestClient(app) + resp = client.post( + "/required-field-alias-and-validation-alias", json={"param_val_alias": "123"} + ) + assert resp.status_code == 200 + # Currently fails due to issue with aliases: + # AssertionError: assert 422 == 200 + + # Uncomment when the assertion above passes: + # assert resp.json() == {"param": "123"} + + +def test_required_field_alias_and_validation_alias_schema(): + openapi = app.openapi() + body_schema = openapi["components"]["schemas"][ + "Body_required_field_alias_and_validation_alias" + ] + assert body_schema["properties"] == { + "param_val_alias": {"title": "Param Val Alias", "type": "string"} + } + + +# ------------------------------ +# optional field + + +@app.post( + "/optional-field-alias-and-validation-alias", + operation_id="optional_field_alias_and_validation_alias", +) +async def optional_field_alias_and_validation_alias( + param: Optional[str] = Body( + None, alias="param_alias", validation_alias="param_val_alias", embed=True + ), +): + return {"param": param} + + +def test_optional_field_alias_and_validation_alias_by_name(): + client = TestClient(app) + resp = client.post( + "/optional-field-alias-and-validation-alias", json={"param": "123"} + ) + assert resp.status_code == 200 + assert resp.json() == {"param": None} + + +@pytest.mark.xfail(raises=AssertionError, strict=False) +def test_optional_field_alias_and_validation_alias_by_alias(): + client = TestClient(app) + resp = client.post( + "/optional-field-alias-and-validation-alias", json={"param_alias": "123"} + ) + assert resp.status_code == 200 + assert resp.json() == {"param": None} + # Currently fails due to issue with aliases: + # AssertionError: assert {'param': '123'} == {'param': None} + + +@pytest.mark.xfail(raises=AssertionError, strict=False) +def test_optional_field_alias_and_validation_alias_by_validation_alias(): + client = TestClient(app) + resp = client.post( + "/optional-field-alias-and-validation-alias", json={"param_val_alias": "123"} + ) + assert resp.status_code == 200 + assert resp.json() == {"param": "123"} + # Currently fails due to issue with aliases: + # AssertionError: assert {'param': None} == {'param': '123'} + + +def test_optional_field_alias_and_validation_alias_schema(): + openapi = app.openapi() + body_schema = openapi["components"]["schemas"][ + "Body_optional_field_alias_and_validation_alias" + ] + assert body_schema["properties"] == { + "param_val_alias": { + "anyOf": [{"type": "string"}, {"type": "null"}], + "title": "Param Val Alias", + } + } + + +# ------------------------------ +# list field + + +@app.post( + "/list-field-alias-and-validation-alias", + operation_id="list_field_alias_and_validation_alias", +) +async def list_field_alias_and_validation_alias( + param: List[str] = Body( + alias="param_alias", validation_alias="param_val_alias", embed=True + ), +): + return {"param": param} + + +@pytest.mark.xfail(raises=AssertionError, strict=False) +def test_list_field_alias_and_validation_alias_by_name(): + client = TestClient(app) + resp = client.post( + "/list-field-alias-and-validation-alias", json={"param": ["123", "456"]} + ) + assert resp.status_code == 422 + detail = resp.json()["detail"] + assert detail[0]["msg"] == "Field required" + assert "param_val_alias" in detail[0]["loc"] + # Currently fails due to issue with aliases: + # AssertionError: assert 'param_val_alias' in ['body', 'param_alias'] + + +@pytest.mark.xfail(raises=AssertionError, strict=False) +def test_list_field_alias_and_validation_alias_by_alias(): + client = TestClient(app) + resp = client.post( + "/list-field-alias-and-validation-alias", json={"param_alias": ["123", "456"]} + ) + assert resp.status_code == 422 + # Currently fails due to issue with aliases: + # AssertionError: assert 200 == 422 + + # Uncomment when the assertion above passes: + # detail = resp.json()["detail"] + # assert detail[0]["msg"] == "Field required" + # assert "param_val_alias" in detail[0]["loc"] + + +@pytest.mark.xfail(raises=AssertionError, strict=False) +def test_list_field_alias_and_validation_alias_by_validation_alias(): + client = TestClient(app) + resp = client.post( + "/list-field-alias-and-validation-alias", + json={"param_val_alias": ["123", "456"]}, + ) + assert resp.status_code == 200 + # Currently fails due to issue with aliases: + # AssertionError: assert 422 == 200 + + # Uncomment when the assertion above passes: + # assert resp.json() == {"param": ["123", "456"]} + + +def test_list_field_alias_and_validation_alias_schema(): + openapi = app.openapi() + body_schema = openapi["components"]["schemas"][ + "Body_list_field_alias_and_validation_alias" + ] + assert body_schema["properties"] == { + "param_val_alias": { + "items": {"type": "string"}, + "title": "Param Val Alias", + "type": "array", + }, + } + + +# ------------------------------ +# optional list field + + +@app.post( + "/optional-list-field-alias-and-validation-alias", + operation_id="optional_list_field_alias_and_validation_alias", +) +async def optional_list_field_alias_and_validation_alias( + param: Optional[List[str]] = Body( + None, alias="param_alias", validation_alias="param_val_alias", embed=True + ), +): + return {"param": param} + + +def test_optional_list_field_alias_and_validation_alias_by_name(): + client = TestClient(app) + resp = client.post( + "/optional-list-field-alias-and-validation-alias", + json={"param": ["123", "456"]}, + ) + assert resp.status_code == 200 + assert resp.json() == {"param": None} + + +@pytest.mark.xfail(raises=AssertionError, strict=False) +def test_optional_list_field_alias_and_validation_alias_by_alias(): + client = TestClient(app) + resp = client.post( + "/optional-list-field-alias-and-validation-alias", + json={"param_alias": ["123", "456"]}, + ) + assert resp.status_code == 200 + assert resp.json() == {"param": None} + # Currently fails due to issue with aliases: + # AssertionError: assert {'param': ['123', '456']} == {'param': None} + + +@pytest.mark.xfail(raises=AssertionError, strict=False) +def test_optional_list_field_alias_and_validation_alias_by_validation_alias(): + client = TestClient(app) + resp = client.post( + "/optional-list-field-alias-and-validation-alias", + json={"param_val_alias": ["123", "456"]}, + ) + assert resp.status_code == 200 + assert resp.json() == {"param": ["123", "456"]} + # Currently fails due to issue with aliases: + # AssertionError: assert {'param': None} == {'param': ['123', '456']} + + +def test_optional_list_field_alias_and_validation_alias_schema(): + openapi = app.openapi() + body_schema = openapi["components"]["schemas"][ + "Body_optional_list_field_alias_and_validation_alias" + ] + assert body_schema["properties"] == { + "param_val_alias": { + "anyOf": [{"items": {"type": "string"}, "type": "array"}, {"type": "null"}], + "title": "Param Val Alias", + }, + } + + +# ===================================================================================== +# Body(alias=..., validation_alias=...) # alias == validation_alias +# The only working solution (current workaround) +# TODO: remove when issue with Body field aliases is fixed + + +@app.post("/workaround", operation_id="workaround") +async def workaround( + param: str = Body(alias="param_alias", validation_alias="param_alias", embed=True), +): + return {"param": param} + + +def test_workaround_by_name(): + client = TestClient(app) + resp = client.post("/workaround", json={"param": "123"}) + assert resp.status_code == 422 + detail = resp.json()["detail"] + assert detail[0]["msg"] == "Field required" + assert "param_alias" in detail[0]["loc"] + + +def test_workaround_by_alias(): + client = TestClient(app) + resp = client.post("/workaround", json={"param_alias": "123"}) + assert resp.status_code == 200 + assert resp.json() == {"param": "123"} + + +def test_workaround_schema(): + openapi = app.openapi() + body_schema = openapi["components"]["schemas"]["Body_workaround"] + assert body_schema["properties"] == { + "param_alias": {"title": "Param Alias", "type": "string"} + } diff --git a/tests/test_aliases/test_body_field_aliases_pd_v1.py b/tests/test_aliases/test_body_field_aliases_pd_v1.py new file mode 100644 index 000000000..9ab8c4ef7 --- /dev/null +++ b/tests/test_aliases/test_body_field_aliases_pd_v1.py @@ -0,0 +1,166 @@ +from typing import List, Optional + +from fastapi import Body, FastAPI +from fastapi._compat import PYDANTIC_V2 +from fastapi.testclient import TestClient + +from ..utils import needs_pydanticv1 + +pytestmark = needs_pydanticv1 + + +app = FastAPI() + +# ===================================================================================== +# Body(alias=...) +# Current situation: Works + +# ------------------------------ +# required field + + +@app.post("/required-field-alias", operation_id="required_field_alias") +async def required_field_alias( + param: str = Body(alias="param_alias", embed=True), +): + return {"param": param} + + +def test_required_field_alias_(): + client = TestClient(app) + resp = client.post("/required-field-alias", json={"param": "123"}) + assert resp.status_code == 422 + detail = resp.json()["detail"] + assert detail[0]["msg"] == "field required" + assert "param_alias" in detail[0]["loc"] + + +def test_required_field_alias_by_alias(): + client = TestClient(app) + resp = client.post("/required-field-alias", json={"param_alias": "123"}) + assert resp.status_code == 200 + assert resp.json() == {"param": "123"} + + +def test_required_field_alias_schema(): + openapi = app.openapi() + body_schema = openapi["components"]["schemas"]["Body_required_field_alias"] + assert body_schema["properties"] == { + "param_alias": {"type": "string", "title": "Param Alias"} + } + + +# ------------------------------ +# optional field + +if not PYDANTIC_V2: + + @app.post("/optional-field-alias", operation_id="optional_field_alias") + async def optional_field_alias( + param: Optional[str] = Body( + None, alias="param_alias", embed=True, nullable=True + ), + ): + return {"param": param} + + +def test_optional_field_alias_by_name(): + client = TestClient(app) + resp = client.post("/optional-field-alias", json={"param": "123"}) + assert resp.status_code == 200 + assert resp.json() == {"param": None} + + +def test_optional_field_alias_by_alias(): + client = TestClient(app) + resp = client.post("/optional-field-alias", json={"param_alias": "123"}) + assert resp.status_code == 200 + assert resp.json() == {"param": "123"} + + +def test_optional_field_alias_schema(): + openapi = app.openapi() + body_schema = openapi["components"]["schemas"]["Body_optional_field_alias"] + assert body_schema["properties"] == { + "param_alias": {"nullable": True, "title": "Param Alias", "type": "string"}, + } + + +# ------------------------------ +# list field + + +@app.post("/list-field-alias", operation_id="list_field_alias") +async def list_field_alias(param: List[str] = Body(alias="param_alias", embed=True)): + return {"param": param} + + +def test_list_field_alias_by_name(): + client = TestClient(app) + resp = client.post("/list-field-alias", json={"param": ["123", "456"]}) + assert resp.status_code == 422 + detail = resp.json()["detail"] + assert detail[0]["msg"] == "field required" + assert "param_alias" in detail[0]["loc"] + + +def test_list_field_alias_by_alias(): + client = TestClient(app) + resp = client.post("/list-field-alias", json={"param_alias": ["123", "456"]}) + assert resp.status_code == 200 + assert resp.json() == {"param": ["123", "456"]} + + +def test_list_field_alias_schema(): + openapi = app.openapi() + body_schema = openapi["components"]["schemas"]["Body_list_field_alias"] + assert body_schema["properties"] == { + "param_alias": { + "items": {"type": "string"}, + "type": "array", + "title": "Param Alias", + } + } + + +# ------------------------------ +# optional list field + +if not PYDANTIC_V2: + + @app.post("/optional-list-field-alias", operation_id="optional_list_field_alias") + async def optional_list_field_alias( + param: Optional[List[str]] = Body( + None, alias="param_alias", embed=True, nullable=True + ), + ): + return {"param": param} + + +def test_optional_list_field_alias_by_name(): + client = TestClient(app) + resp = client.post("/optional-list-field-alias", json={"param": ["123", "456"]}) + assert resp.status_code == 200 + assert resp.json() == {"param": None} + + +def test_optional_list_field_alias_by_alias(): + client = TestClient(app) + resp = client.post( + "/optional-list-field-alias", json={"param_alias": ["123", "456"]} + ) + assert resp.status_code == 200 + assert resp.json() == {"param": ["123", "456"]} + + +def test_optional_list_field_alias_schema(): + openapi = app.openapi() + body_schema = openapi["components"]["schemas"]["Body_optional_list_field_alias"] + assert body_schema["properties"] == { + "param_alias": { + "nullable": True, + "items": {"type": "string"}, + "type": "array", + "title": "Param Alias", + }, + }