I'm trying to insert an item card into timeline with an image as attachment.
If I try to insert an item, it goes well:
def notify_card(my_user, card=None):
payload = card
headers = {'Content-Type': 'application/json',
'Authorization': 'Bearer {0}'.format(my_user.mirror_access_token)}
url = OAUTH_API_BASE_URL + '/mirror/v1/timeline'
r = requests.post(url, data=payload, headers=headers)
if r.status_code == 401:
new_access_token = __refresh_token(my_user.mirror_refresh_token)
__create_or_update_user(access_token=new_access_token, refresh_token=user_vademecum.mirror_refresh_token)
headers = {'Content-Type': 'application/json',
'Authorization': 'Bearer {0}'.format(new_access_token)}
r = requests.post(url, data=payload, headers=headers)
This works fine, an insert the card into the timeline.
The problem comes now, when I want to upload an image:
# Send media
import os
module_dir = os.path.dirname(__file__) # get current directory
file_path = os.path.join(module_dir, 'bodegon.jpg')
file = {'bodegon.jpg': ('bodegon.jpg', open(file_path, 'rb'), 'image/jpg')}
headers = {
'Authorization': 'Bearer {0}'.format(my_user.mirror_access_token)}
url = OAUTH_API_BASE_URL + 'upload/mirror/v1/timeline?uploadType=multipart'
r = requests.post(url, data={"message": {"bundleId": "0000001"}}, files=file, headers=headers)
print r.text
This code returns the error message:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "badContent",
"message": "Media type 'application/octet-stream' is not supported. Valid media types: [image/*, audio/*, video/*]"
}
],
"code": 400,
"message": "Media type 'application/octet-stream' is not supported. Valid media types: [image/*, audio/*, video/*]"
}
}
If I set manually the content type:
headers = {'content-type': 'image/jpg',
'Authorization': 'Bearer {0}'.format(my_user.mirror_access_token)}
This message is returned:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "required",
"message": "Required"
}
],
"code": 400,
"message": "Required"
}
}
Also, I have try to send the media to this url:
https://www.googleapis.com/upload/mirror/v1/timeline?uploadType=media
instead of
https://www.googleapis.com/upload/mirror/v1/timeline?uploadType=multipart
In order to upload using the simple upload: https://developers.google.com/glass/media-upload
What I'm doing wrong?
Using the code you provided, requests will generate a request body roughly like:
--{boundary}
Content-Disposition: form-data; message="message"
bundleId
--{boundary}
Content-Disposition: form-data; name="bodegon.jpg"
{file contents}
--{boundary}--
Notice that the id you specify for bundleId
does not appear. This means you may want it to be JSON encoded data as @Prisoner seems to suggest in his answer. Further judging by your question you need to provide a Content-Type
for the file part of the upload. This can be solved like so:
import json
r = requests.post(url, files={"message": (, json.dumps({"bundleId": "0000001"}, 'application/json'), 'file': ('filename.jpg', file, 'image/jpeg')}, headers=headers)
Where headers
is the original dictionary you specified.
Also, if you're uploading very large files you may want to consider not using requests alone for this. The file will be loaded into memory in its entirety. In a case like this you will most likely wish to stream the upload. You can use requests-toolbelt like so:
import requests
from requests_toolbelt import MultipartEncoder
import json
fields = {
'message': (, json.dumps({'bundleId': '0000001'}, 'application/json'),
'file': ('filename.jpg', file, 'image/jpeg')
}
encoder = MultipartEncoder(fields)
headers = {
'Authorization': 'Bearer <your token>',
'Content-Type': encoder.content_type
}
r = requests.post(url, data=encoder, headers=headers)
This will take care of encoding the data and allowing it to be streamed to the server.
Note I did not check the names of the form parts with the documentation so using 'file'
may not be right. I encourage you to look into this yourself.