I have built an API using FastAPI and am trying to send data to it from a client.
Both the API and the client use a similar Pydantic model for the data that I want to submit. This includes a field that contains a file path, which I store in a field of type pathlib.path.
However, FastAPI does not accept the submission because it apparently cannot handle the path object:
TypeError: Object of type PosixPath is not JSON serializable
Here's a minimal test file that shows the problem:
import pathlib
from pydantic import BaseModel
from fastapi import FastAPI
from fastapi.testclient import TestClient
api = FastAPI()
client = TestClient(api)
class Submission(BaseModel):
file_path: pathlib.Path
@api.post("/", response_model=Submission)
async def add_submission(subm: Submission):
print(subm)
# add submission to database
return subm
def test_add_submission():
data = {"file_path": "/my/path/to/file.csv"}
print("original data:", data)
# create a Submission object, which casts filePath to pathlib.Path:
submission = Submission(**data)
print("submission object:", submission)
payload = submission.dict()
print("payload:", payload)
response = client.post("/", json=payload) # this throws the error
assert response.ok
test_add_submission()
When I change the model on the client side to use a string instead of a Path for file_path, things go through. But then I lose the pydantic power of casting the input to a Path when a Submission object is created, and then having a Path attribute with all its possibilities. Surely, there must be better way?
What is the correct way to send a pathlib.PosixPath object to a FastAPI API as part of the payload?
(This is Python 3.8.9, fastapi 0.68.1, pydantic 1.8.2 on Ubuntu)
The problem with you code is, that you first transform the pydantic model into a dict, which you then pass to the client, which uses its own json serializer and not the one provided by pydantic.
submission.dict() converts any pydantic model into a dict but keeps any other datatype.
With client.post("/", json=payload) requests json serializer is used, which cannot handle pathlib.Path.
The solution is, not to convert the pydantic model into dict first, but use the json() method of the pydantic model itself and pass it to the client.
response = client.post("/", data=submission.json())
Notice that you have to change the parameter json to data.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With