mirror of https://github.com/tiangolo/fastapi.git
Refactor JSON error handling in routing and tests for improvements.
This commit is contained in:
parent
dc1321b0d0
commit
5c4055c3ea
|
|
@ -266,10 +266,6 @@ def get_request_handler(
|
|||
else:
|
||||
body = body_bytes
|
||||
except json.JSONDecodeError as e:
|
||||
lines_before = e.doc[: e.pos].split("\n")
|
||||
line_number = len(lines_before)
|
||||
column_number = len(lines_before[-1]) + 1 if lines_before else 1
|
||||
|
||||
start_pos = max(0, e.pos - 40)
|
||||
end_pos = min(len(e.doc), e.pos + 40)
|
||||
error_snippet = e.doc[start_pos:end_pos]
|
||||
|
|
@ -282,14 +278,15 @@ def get_request_handler(
|
|||
[
|
||||
{
|
||||
"type": "json_invalid",
|
||||
"loc": ("body", line_number, column_number),
|
||||
"msg": f"JSON decode error - {e.msg} at line {line_number}, column {column_number}",
|
||||
"input": error_snippet,
|
||||
"loc": ("body", e.pos),
|
||||
"msg": "JSON decode error",
|
||||
"input": {},
|
||||
"ctx": {
|
||||
"error": e.msg,
|
||||
"position": e.pos,
|
||||
"line": line_number,
|
||||
"column": column_number,
|
||||
"line": e.lineno - 1,
|
||||
"column": e.colno - 1,
|
||||
"snippet": error_snippet,
|
||||
},
|
||||
}
|
||||
],
|
||||
|
|
|
|||
|
|
@ -30,12 +30,14 @@ def test_json_decode_error_single_line():
|
|||
assert response.status_code == 422
|
||||
error = response.json()["detail"][0]
|
||||
|
||||
assert error["loc"] == ["body", 1, 27]
|
||||
assert "line 1" in error["msg"]
|
||||
assert "column 27" in error["msg"]
|
||||
assert error["ctx"]["line"] == 1
|
||||
assert error["ctx"]["column"] == 27
|
||||
assert "None" in error["input"]
|
||||
assert error["loc"] == ["body", 26]
|
||||
assert error["msg"] == "JSON decode error"
|
||||
assert error["input"] == {}
|
||||
assert error["ctx"]["error"] == "Expecting value"
|
||||
assert error["ctx"]["position"] == 26
|
||||
assert error["ctx"]["line"] == 0
|
||||
assert error["ctx"]["column"] == 26
|
||||
assert "None" in error["ctx"]["snippet"]
|
||||
|
||||
|
||||
def test_json_decode_error_multiline():
|
||||
|
|
@ -52,12 +54,13 @@ def test_json_decode_error_multiline():
|
|||
assert response.status_code == 422
|
||||
error = response.json()["detail"][0]
|
||||
|
||||
assert error["loc"] == ["body", 4, 12]
|
||||
assert "line 4" in error["msg"]
|
||||
assert "column 12" in error["msg"]
|
||||
assert error["ctx"]["line"] == 4
|
||||
assert error["ctx"]["column"] == 12
|
||||
assert "invalid" in error["input"]
|
||||
assert error["loc"][0] == "body"
|
||||
assert isinstance(error["loc"][1], int)
|
||||
assert error["msg"] == "JSON decode error"
|
||||
assert error["input"] == {}
|
||||
assert error["ctx"]["line"] == 3
|
||||
assert error["ctx"]["column"] == 11
|
||||
assert "invalid" in error["ctx"]["snippet"]
|
||||
|
||||
|
||||
def test_json_decode_error_shows_snippet():
|
||||
|
|
@ -70,9 +73,10 @@ def test_json_decode_error_shows_snippet():
|
|||
assert response.status_code == 422
|
||||
error = response.json()["detail"][0]
|
||||
|
||||
assert "..." in error["input"]
|
||||
assert "invalid" in error["input"]
|
||||
assert len(error["input"]) <= 83
|
||||
assert error["msg"] == "JSON decode error"
|
||||
assert error["input"] == {}
|
||||
assert "invalid" in error["ctx"]["snippet"]
|
||||
assert len(error["ctx"]["snippet"]) <= 83
|
||||
|
||||
|
||||
def test_json_decode_error_empty_body():
|
||||
|
|
@ -117,10 +121,13 @@ def test_json_decode_error_unclosed_brace():
|
|||
assert response.status_code == 422
|
||||
error = response.json()["detail"][0]
|
||||
|
||||
assert "line" in error["msg"].lower()
|
||||
assert "column" in error["msg"].lower()
|
||||
assert error["msg"] == "JSON decode error"
|
||||
assert error["type"] == "json_invalid"
|
||||
assert error["input"] == {}
|
||||
assert "position" in error["ctx"]
|
||||
assert "line" in error["ctx"]
|
||||
assert "column" in error["ctx"]
|
||||
assert "snippet" in error["ctx"]
|
||||
|
||||
|
||||
def test_json_decode_error_in_middle_of_long_document():
|
||||
|
|
@ -135,9 +142,10 @@ def test_json_decode_error_in_middle_of_long_document():
|
|||
assert response.status_code == 422
|
||||
error = response.json()["detail"][0]
|
||||
|
||||
# The error snippet should have "..." at the end since error is early in doc
|
||||
assert error["input"].endswith("...")
|
||||
assert "invalid" in error["input"]
|
||||
assert error["msg"] == "JSON decode error"
|
||||
assert error["input"] == {}
|
||||
assert error["ctx"]["snippet"].endswith("...")
|
||||
assert "invalid" in error["ctx"]["snippet"]
|
||||
assert error["type"] == "json_invalid"
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -206,14 +206,15 @@ def test_post_broken_body(client: TestClient):
|
|||
"detail": [
|
||||
{
|
||||
"type": "json_invalid",
|
||||
"loc": ["body", 1, 2],
|
||||
"msg": "JSON decode error - Expecting property name enclosed in double quotes at line 1, column 2",
|
||||
"input": "{some broken json}",
|
||||
"loc": ["body", 1],
|
||||
"msg": "JSON decode error",
|
||||
"input": {},
|
||||
"ctx": {
|
||||
"error": "Expecting property name enclosed in double quotes",
|
||||
"position": 1,
|
||||
"line": 1,
|
||||
"column": 2,
|
||||
"line": 0,
|
||||
"column": 1,
|
||||
"snippet": "{some broken json}",
|
||||
},
|
||||
}
|
||||
]
|
||||
|
|
|
|||
Loading…
Reference in New Issue