4

I am trying to upload JSON data + file (binary) to FastAPI 'POST' endpoint using requests.

This is the server code:

@app.post("/files/")
async def create_file(
    file: bytes = File(...), fileb: UploadFile = File(...), timestamp: str = Form(...)
):
    return {
        "file_size": len(file),
        "timestamp": timestamp,
        "fileb_content_type": fileb.content_type,
    }

This is the client code:

session = requests.Session()
adapter = requests.adapters.HTTPAdapter(max_retries=0)
session.mount('http://', adapter)

jpg_image = open(IMG_PATH, 'rb').read()

timestamp_str = datetime.datetime.now().isoformat()
files = {
    'timestamp': (None, timestamp_str),
    'file': ('image.jpg', jpg_image),
}
request = requests.Request('POST',
                           FILE_UPLOAD_ENDPOINT,
                           files=files)
prepared_request = request.prepare()
response = session.send(prepared_request)

The server fails with

"POST /files/ HTTP/1.1" 422 Unprocessable Entity

Alex Gill
  • 179
  • 1
  • 8
  • Please add the 422 response's body in your question for clarity. – John Moutafis Jan 14 '21 at 10:19
  • 1
    For what it's worth , the response with status `422` comes from `fastapi.exception_handlers.request_validation_exception_handler(req, exc)` , if you are on development stage , you can set breakpoint then get more detail about the error from `exc` (the exception object) , the exception should describe that there is a missing field `fileb` , which means in your client code you should also specify the same field name `fileb` in the request body – Ham Jun 20 '21 at 05:13
  • If you are trying to upload both JSON data and file(s), as mentioned in the question, please have a look at [this answer](https://stackoverflow.com/a/70640522/17865804) as well – Chris Jun 23 '23 at 04:45

1 Answers1

3

FastAPI endpoints usually respond 422 when the request body is missing a required field, or there are non-expected fields, etc.

It seems that you are missing the fileb from your request body.

  • If this field is optional, you must declare it as follows in the endpoint definition:

    fileb: Optional[UploadFile] = File(None)
    

    You will also need to make some checks inside your endpoint code...

  • If it is a required field then you need to add it to your request body.

John Moutafis
  • 22,254
  • 11
  • 68
  • 112
  • 1
    Thanks @JohnMoutafis for the response. I fixed the endpoint to match the request and it worked. The correct code is: `@app.post("/files/", status_code=201) async def create_file( file: bytes = File(...), timestamp: str = Form(...), ):` – Alex Gill Jan 17 '21 at 07:38