chatzich
chatzich

Reputation: 1133

How to upload file to flask application with python requests

I have the following curl command

curl -X POST "http://localhost:5000/api/v1/image/cad1b12e-c374-4d46-b43b-3ddbe7d683c4" -H  "accept: application/json" -H  "Content-Type: multipart/form-data" -F "file=@tests/test.jpg;type=image/jpeg"

I am trying to construct a pytest function with the same behavior that the command above but I am not getting the exact result, the pytest function is the following

url = "http://localhost:5000/api/v1/image/cad1b12e-c374-4d46-b43b-3ddbe7d683c4"

payload={}

files=[('file',('test.png',open('./tests/test.png','rb'),'image/png'))]
headers = {
    'accept': 'application/json',
    'Content-Type': 'multipart/form-data'
}

response = requests.request("POST", url, headers=headers, data=payload, files=files)

Upvotes: 1

Views: 1494

Answers (1)

v25
v25

Reputation: 7621

Short answer:

Don't specify a Content-Type in the headers dictionary, when providing a files argument to the requests.request method.

Longer answer

I tried to test that functionality to my own Flask upload script.

This worked when removing 'Content-Type': 'multipart/form-data' form the headers dictionary, otherwise the response was 400 bad request (see response.content)

I noted that after making the request, and inspecting response.request.headers I could see that

  • when specifying that header it was part of the request, as-is:

     'Content-Type': 'multipart/form-data'
    
  • however when not specifying it requests automatically generates the header with a boundary, and the request succeeded:

     'Content-Type': 'multipart/form-data; boundary=1beba22d28ce1e2cdcd76d253f8ef1fe'
    

Also:

  • To find the headers sent from curl, either by using the trace method or if you have access to the server, printing request.headers within the upload route, you can see that the curl command automatically appends a boundary to the header, even when the flag -H "Content-Type: multipart/form-data" is provided:

      Content-Type: multipart/form-data; boundary=------------------------c263b5b9297c78d3
    
  • The same can be observed via the Network tab in your browser dev-tools, when uploading via an HTML form with enctype="multipart/form-data" set as an attribute.


I had always thought that manually adding 'Content-Type:':'multipart/form-data' to the headers dict was required, but it appears when using the the files argument to requests.request method, this is automatically generated with the boundary.

In fact the requests docs make no mention of setting this header yourself.

Upvotes: 1

Related Questions