Pydantic and FastAPI fail when a field contains unicode characters

When a FastAPI endpoint expects a Pydantic model and one is passed with a string it works as expected unless that string contains unicode characters. First I create an example application for FastAPI …

问题描述:

When a FastAPI endpoint expects a Pydantic model and one is passed with a string it works as expected unless that string contains unicode characters.

First I create an example application for FastAPI with an example model.
serv.py

from pydantic import BaseModel


class exClass(BaseModel):
    id: int = Field(example=1)
    text: str = Field(example="Text example")

app = FastAPI(debug=True)

@app.post("/example")
async def receive_pyd(ex: exClass):
    print(ex)
    return True

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="127.0.0.1", port=8000)

The client that shows the error in question client.py

from pydantic import BaseModel, Field
import requests

class exClass(BaseModel):
    id: int = Field(example=1)
    text: str = Field(example="Text example")


ex1 = exClass(id=1, text="working example")
ex2 = exClass(id=2, text="this’ will fail")
ex3 = exClass(id=3, text="🤗 <- also non-working")


r = requests.post(f"http://127.0.0.1:8000/example", data=ex1.model_dump_json())
print(r.text)
r = requests.post(f"http://127.0.0.1:8000/example", data=ex2.model_dump_json())
print(r.text)
r = requests.post(f"http://127.0.0.1:8000/example", data=ex3.model_dump_json())
print(r.text)

Output:

true
Invalid HTTP request received.
Invalid HTTP request received.

When text contains unicode characters the result is a 422 Unprocessable Entity. I have tried ex.dict(), model_dump(), and using json instead of data in the requests call. Enabling debugging in FastAPI/starlette bubbles up that the Invalid HTTP request is a JSON decode error.

解决方案 1[最佳方案][1]

This is not a problem of Pydantic and FastAPI. You should encode you request data like it’s shown below:

r = requests.post(
    f"http://127.0.0.1:8000/example", data=ex1.model_dump_json().encode('utf-8')
)
print(r.text)
r = requests.post(
    f"http://127.0.0.1:8000/example", data=ex2.model_dump_json().encode('utf-8')
)
print(r.text)
r = requests.post(
    f"http://127.0.0.1:8000/example", data=ex3.model_dump_json().encode('utf-8')
)
print(r.text)

解决方案 2:[2]

When sending JSON data from Python requests, one should use the json argument to pass a valid dictionary. Using that argument would set the request’s Content-Type header to application/json. The data argument, on the other hand, is used when sending form data, and these data are encoded with application/x-www-form-urlencoded (that is the default Content-Type in requests), or multipart/form-data (if files are included in the request as well). Please have a look at this answer and this answer. You might find this, as well as this and this helpful as well.

Along with setting the Content-Type header to application/json, you should use Pydantic’s model_dump() method (see this answer for more details)—instead of model_dump_json()—which would convert the model to a dictionary.

Example

# ... rest of the code is the same as given in the question

url = 'http://127.0.0.1:8000/example'

r = requests.post(url, json=ex1.model_dump())
print(r.text)
r = requests.post(url, json=ex2.model_dump())
print(r.text)
r = requests.post(url, json=ex3.model_dump())
print(r.text)

参考链接:

Copyright Notice: This article follows StackOverflow’s copyright notice requirements and is licensed under CC BY-SA 3.0.

Article Source: StackOverflow

[1] Yurii Motov

[2] Chris

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
青葱年少的头像青葱年少普通用户
上一篇 2023年12月13日
下一篇 2023年12月13日

相关推荐