Home > Enterprise >  Is there a way of sending an multipart/form-data array using python requests?
Is there a way of sending an multipart/form-data array using python requests?

Time:11-19

Assume there's an endpoint accepting HTTP requests with multipart/form-data content-type. Here's the example of the body of an acceptable request.

----------------------------033392576939750140334380
Content-Disposition: form-data; name="file" filename="dummy_file.txt"
Some dummy file here.
----------------------------033392576939750140334380
Content-Disposition: form-data; name="years"
2019
----------------------------033392576939750140334380
Content-Disposition: form-data; name="years"
2020
----------------------------033392576939750140334380

As you can see, there's an array of numbers that are being sent using years keyword.

The questions is how can we send the same request using requests library in python? It seems to be pretty tricky because of that years array.

I've tried to send it these ways.

requests.post(
        "http://some.site/some-endpoint/",
        files={
            "years": [2019, 2020],
            "file": ("dummy_file.txt", open("dummy_file.txt", "rb")),
        },
    )

Not going to work - TypeError: a bytes-like object is required, not 'list'.


requests.post(
        "http://some.site/some-endpoint/",
        files={
            "years": (None, "2019, 2020"),
            "file": ("dummy_file.txt", open("dummy_file.txt", "rb")),
        },
    )

Gives the following request body.

--88c0aa2588fb3ca9b1e3c9c6cf625677
Content-Disposition: form-data; name="years"
2019, 2020
--88c0aa2588fb3ca9b1e3c9c6cf625677
Content-Disposition: form-data; name="file"; filename="dummy_file.txt"
Some dummy file here.
--88c0aa2588fb3ca9b1e3c9c6cf625677--

The years array is represented here as the string value which is not okay for this case.


requests.post(
        "http://some.site/some-endpoint/",
        files={
            "years[0]": (None, "2020"),
            "years[1]": (None, "2019"),
            "file": ("dummy_file.txt", open("dummy_file.txt", "rb")),
        },
    )

Gives the following request body.

--989f55fc01395402654f4275d11e8735
Content-Disposition: form-data; name="years[0]"
2020
--989f55fc01395402654f4275d11e8735
Content-Disposition: form-data; name="years[1]"
2019
Content-Disposition: form-data; name="file"; filename="dummy_file.txt"
Some dummy file here.
--989f55fc01395402654f4275d11e8735

This way every element in the years array is represented by a different name, which is also not suitable for this particular case.


If we examine the last attempt it seems that we can achieve the required body structure by sending each value of years array using the same years keyword. But that's not going to work with requests as the files attribute accepts dict object which only allows unique keys.

So, how can we achieve this using requests module?

CodePudding user response:

I found this in the docs: https://requests.readthedocs.io/en/latest/user/quickstart/#more-complicated-post-requests

Use a list of tuples to create the mapping, not a dict:

r = requests.post(
    "https://httpbin.org/anything",
    files=[
        ("file", ("dummy_file.txt", b"File content....")),    
        ("years", (None, 2019)),
        ("years", (None, 2020)),
    ]
)

Data sent in r.request.body:

--8d763b42e4adf30aaefb9657df8bcf1b
Content-Disposition: form-data; name="file"; filename="dummy_file.txt"

File content....
--8d763b42e4adf30aaefb9657df8bcf1b
Content-Disposition: form-data; name="years"

2019
--8d763b42e4adf30aaefb9657df8bcf1b
Content-Disposition: form-data; name="years"

2020
--8d763b42e4adf30aaefb9657df8bcf1b--
  • Related