jahmezz
jahmezz

Reputation: 416

send multipart upload with json

I'm trying to upload a video file along with some JSON using a REST API with requests in Python.

Here is the example cURL for the request.

curl -XPOST -i "https://io.cimediacloud.com/upload" \
-H "Authorization: Bearer ACCESS_TOKEN" \
-F [email protected]
-F metadata="{ 'metadata' : { 'Resolution' : '1080p', 'Language' : 'English' },        
'workspaceId' : 'a585b641a60843498543597d16ba0108', 'folderId' : 
'a585b641a60843498543597d16ba0108' }"

And here is my code.

url = 'https://io.cimediacloud.com/upload'
files = {'file': ('video.mp4', open('files/video.mp4', 'rb')),
                  }
data = {'metadata': {'Resolution' : '1080p', 'Language' : 'English'},
        'workspaceId': your_workspace_id,
        'folderId': folder_id,}

r = session.post(url, files=files, data=data)

When I run this, the API server returns a MissingOrInvalidFileName error. If I leave out my data parameter, the file uploads correctly. What is the correct way to make this request?

Upvotes: 0

Views: 2568

Answers (2)

jahmezz
jahmezz

Reputation: 416

Finally solved! Turns out requests encodes its multipart with data then files while the API required files then data.

@Martijn Pieters's solution of inputting all of the data as tuples almost works. The only problem is setting the data this way breaks requests' ability to set the content-type header automatically (it thinks my data is content-type application/json).

In the end, I used request-toolbelt's MultipartEncoder which allows me to order my multipart body using tuples and saves the content-type in its instance. Here is the final working code.

m = MultipartEncoder([('filename', ('video.mp4', open('files/video.mp4', 'rb'))), 
                      ('metadata', json.dumps(metadata))])

r = session.post(url, data=m, headers={'Content-Type': m.content_type})

Finally works.

Upvotes: 1

Martijn Pieters
Martijn Pieters

Reputation: 1121914

Your file parameter is called filename in the curl request, and the metadata part should be a string (encoded to JSON); it is one field and has a nested metadata object. wordspaceId and folderId are keys in the outermost metadata object, not separate parameters:

import json

files = {'filename': ('video.mp4', open('files/video.mp4', 'rb')),
metadata = {
    'metadata': {'Resolution': '1080p', 'Language': 'English'},
    'workspaceId': your_workspace_id,
    'folderId': folder_id
}
data = {'metadata': json.dumps(metadata)}
r = session.post(url, files=files, data=data)

Upvotes: 2

Related Questions