Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions fastapi/routing.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import asyncio
import email.message
import enum
import inspect
import json
Expand Down Expand Up @@ -36,7 +37,7 @@
)
from pydantic import BaseModel
from pydantic.error_wrappers import ErrorWrapper, ValidationError
from pydantic.fields import ModelField
from pydantic.fields import ModelField, Undefined
from starlette import routing
from starlette.concurrency import run_in_threadpool
from starlette.exceptions import HTTPException
Expand Down Expand Up @@ -174,14 +175,26 @@ def get_request_handler(

async def app(request: Request) -> Response:
try:
body = None
body: Any = None
if body_field:
if is_body_form:
body = await request.form()
else:
body_bytes = await request.body()
if body_bytes:
body = await request.json()
json_body: Any = Undefined
content_type_value = request.headers.get("content-type")
if content_type_value:
message = email.message.Message()
message["content-type"] = content_type_value
if message.get_content_maintype() == "application":
subtype = message.get_content_subtype()
if subtype == "json" or subtype.endswith("+json"):
json_body = await request.json()
if json_body != Undefined:
body = json_body
else:
body = body_bytes
except json.JSONDecodeError as e:
raise RequestValidationError([ErrorWrapper(e, ("body", e.pos))], body=e.doc)
except Exception as e:
Expand Down
84 changes: 75 additions & 9 deletions tests/test_tutorial/test_body/test_tutorial001.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,25 +173,91 @@ def test_post_body(path, body, expected_status, expected_response):


def test_post_broken_body():
response = client.post("/items/", data={"name": "Foo", "price": 50.5})
response = client.post(
"/items/",
headers={"content-type": "application/json"},
data="{some broken json}",
)
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["body", 1],
"msg": "Expecting property name enclosed in double quotes: line 1 column 2 (char 1)",
"type": "value_error.jsondecode",
"ctx": {
"colno": 1,
"doc": "name=Foo&price=50.5",
"msg": "Expecting property name enclosed in double quotes",
"doc": "{some broken json}",
"pos": 1,
"lineno": 1,
"msg": "Expecting value",
"pos": 0,
"colno": 2,
},
"loc": ["body", 0],
"msg": "Expecting value: line 1 column 1 (char 0)",
"type": "value_error.jsondecode",
}
]
}


def test_post_form_for_json():
response = client.post("/items/", data={"name": "Foo", "price": 50.5})
assert response.status_code == 422, response.text
assert response.json() == {
"detail": [
{
"loc": ["body"],
"msg": "value is not a valid dict",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be considered a breaking change. Think even my work API has a test similar to this.

"type": "type_error.dict",
}
]
}


def test_explicit_content_type():
response = client.post(
"/items/",
data='{"name": "Foo", "price": 50.5}',
headers={"Content-Type": "application/json"},
)
assert response.status_code == 200, response.text


def test_geo_json():
response = client.post(
"/items/",
data='{"name": "Foo", "price": 50.5}',
headers={"Content-Type": "application/geo+json"},
)
assert response.status_code == 200, response.text


def test_wrong_headers():
data = '{"name": "Foo", "price": 50.5}'
invalid_dict = {
"detail": [
{
"loc": ["body"],
"msg": "value is not a valid dict",
"type": "type_error.dict",
}
]
}

response = client.post("/items/", data=data, headers={"Content-Type": "text/plain"})
assert response.status_code == 422, response.text
assert response.json() == invalid_dict

response = client.post(
"/items/", data=data, headers={"Content-Type": "application/geo+json-seq"}
)
assert response.status_code == 422, response.text
assert response.json() == invalid_dict
response = client.post(
"/items/", data=data, headers={"Content-Type": "application/not-really-json"}
)
assert response.status_code == 422, response.text
assert response.json() == invalid_dict


def test_other_exceptions():
with patch("json.loads", side_effect=Exception):
response = client.post("/items/", json={"test": "test2"})
assert response.status_code == 400, response.text
assert response.json() == {"detail": "There was an error parsing the body"}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def test_gzip_request(compress):
if compress:
data = gzip.compress(data)
headers["Content-Encoding"] = "gzip"
headers["Content-Type"] = "application/json"
response = client.post("/sum", data=data, headers=headers)
assert response.json() == {"sum": n}

Expand Down