Browse Source

🐛 Fix body validation error response, remove variable name when it is not embedded (#1553)

pull/1576/head
Andrew 5 years ago
committed by GitHub
parent
commit
12bc9285f7
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      docs/en/docs/tutorial/handling-errors.md
  2. 24
      fastapi/dependencies/utils.py
  3. 10
      tests/test_multi_body_errors.py
  4. 14
      tests/test_tutorial/test_body/test_tutorial001.py
  5. 2
      tests/test_tutorial/test_body_nested_models/test_tutorial009.py
  6. 2
      tests/test_tutorial/test_custom_request_and_route/test_tutorial002.py
  7. 2
      tests/test_tutorial/test_handling_errors/test_tutorial005.py

1
docs/en/docs/tutorial/handling-errors.md

@ -215,7 +215,6 @@ You will receive a response telling you that the data is invalid containing the
{
"loc": [
"body",
"item",
"size"
],
"msg": "value is not a valid integer",

24
fastapi/dependencies/utils.py

@ -642,9 +642,17 @@ async def request_body_to_args(
field = required_params[0]
field_info = get_field_info(field)
embed = getattr(field_info, "embed", None)
if len(required_params) == 1 and not embed:
field_alias_omitted = len(required_params) == 1 and not embed
if field_alias_omitted:
received_body = {field.alias: received_body}
for field in required_params:
loc: Tuple[str, ...]
if field_alias_omitted:
loc = ("body",)
else:
loc = ("body", field.alias)
value: Any = None
if received_body is not None:
if (
@ -655,7 +663,7 @@ async def request_body_to_args(
try:
value = received_body.get(field.alias)
except AttributeError:
errors.append(get_missing_field_error(field.alias))
errors.append(get_missing_field_error(loc))
continue
if (
value is None
@ -667,7 +675,7 @@ async def request_body_to_args(
)
):
if field.required:
errors.append(get_missing_field_error(field.alias))
errors.append(get_missing_field_error(loc))
else:
values[field.name] = deepcopy(field.default)
continue
@ -686,7 +694,9 @@ async def request_body_to_args(
awaitables = [sub_value.read() for sub_value in value]
contents = await asyncio.gather(*awaitables)
value = sequence_shape_to_type[field.shape](contents)
v_, errors_ = field.validate(value, values, loc=("body", field.alias))
v_, errors_ = field.validate(value, values, loc=loc)
if isinstance(errors_, ErrorWrapper):
errors.append(errors_)
elif isinstance(errors_, list):
@ -696,12 +706,12 @@ async def request_body_to_args(
return values, errors
def get_missing_field_error(field_alias: str) -> ErrorWrapper:
def get_missing_field_error(loc: Tuple[str, ...]) -> ErrorWrapper:
if PYDANTIC_1:
missing_field_error = ErrorWrapper(MissingError(), loc=("body", field_alias))
missing_field_error = ErrorWrapper(MissingError(), loc=loc)
else: # pragma: no cover
missing_field_error = ErrorWrapper( # type: ignore
MissingError(), loc=("body", field_alias), config=BaseConfig,
MissingError(), loc=loc, config=BaseConfig,
)
return missing_field_error

10
tests/test_multi_body_errors.py

@ -104,7 +104,7 @@ single_error = {
"detail": [
{
"ctx": {"limit_value": 0.0},
"loc": ["body", "item", 0, "age"],
"loc": ["body", 0, "age"],
"msg": "ensure this value is greater than 0",
"type": "value_error.number.not_gt",
}
@ -114,22 +114,22 @@ single_error = {
multiple_errors = {
"detail": [
{
"loc": ["body", "item", 0, "name"],
"loc": ["body", 0, "name"],
"msg": "field required",
"type": "value_error.missing",
},
{
"loc": ["body", "item", 0, "age"],
"loc": ["body", 0, "age"],
"msg": "value is not a valid decimal",
"type": "type_error.decimal",
},
{
"loc": ["body", "item", 1, "name"],
"loc": ["body", 1, "name"],
"msg": "field required",
"type": "value_error.missing",
},
{
"loc": ["body", "item", 1, "age"],
"loc": ["body", 1, "age"],
"msg": "value is not a valid decimal",
"type": "type_error.decimal",
},

14
tests/test_tutorial/test_body/test_tutorial001.py

@ -94,7 +94,7 @@ def test_openapi_schema():
price_missing = {
"detail": [
{
"loc": ["body", "item", "price"],
"loc": ["body", "price"],
"msg": "field required",
"type": "value_error.missing",
}
@ -104,7 +104,7 @@ price_missing = {
price_not_float = {
"detail": [
{
"loc": ["body", "item", "price"],
"loc": ["body", "price"],
"msg": "value is not a valid float",
"type": "type_error.float",
}
@ -114,12 +114,12 @@ price_not_float = {
name_price_missing = {
"detail": [
{
"loc": ["body", "item", "name"],
"loc": ["body", "name"],
"msg": "field required",
"type": "value_error.missing",
},
{
"loc": ["body", "item", "price"],
"loc": ["body", "price"],
"msg": "field required",
"type": "value_error.missing",
},
@ -128,11 +128,7 @@ name_price_missing = {
body_missing = {
"detail": [
{
"loc": ["body", "item"],
"msg": "field required",
"type": "value_error.missing",
}
{"loc": ["body"], "msg": "field required", "type": "value_error.missing",}
]
}

2
tests/test_tutorial/test_body_nested_models/test_tutorial009.py

@ -95,7 +95,7 @@ def test_post_invalid_body():
assert response.json() == {
"detail": [
{
"loc": ["body", "weights", "__key__"],
"loc": ["body", "__key__"],
"msg": "value is not a valid integer",
"type": "type_error.integer",
}

2
tests/test_tutorial/test_custom_request_and_route/test_tutorial002.py

@ -18,7 +18,7 @@ def test_exception_handler_body_access():
"body": '{"numbers": [1, 2, 3]}',
"errors": [
{
"loc": ["body", "numbers"],
"loc": ["body"],
"msg": "value is not a valid list",
"type": "type_error.list",
}

2
tests/test_tutorial/test_handling_errors/test_tutorial005.py

@ -92,7 +92,7 @@ def test_post_validation_error():
assert response.json() == {
"detail": [
{
"loc": ["body", "item", "size"],
"loc": ["body", "size"],
"msg": "value is not a valid integer",
"type": "type_error.integer",
}

Loading…
Cancel
Save