Uploading photo to Google Photos API not returning upload token
Asked Answered
G

3

6

I'm using the 2018 version of the Google Photos API to upload images and media as documented here: "Uploading Bytes"

When I upload a new image or video I never get an upload token in the body of the response. It's always an empty body, which according to the above link means that the bytes have already been uploaded (but this is a new upload).

Here's an example request/response:

request: 
    POST https://photoslibrary.googleapis.com/v1/uploads
request headers: 
    authorization: Bearer abcd1234
    X-Goog-Upload-Protocol: raw
    X-Goog-Upload-File-Name: 20140317T082917_001.jpg
    content-type: application/octet-stream
    content-length: 1292868
    accept: application/json
-----------------------------------------------------
response: OK [200]
response headers:
    Alt-Svc: [quic=":443"; ma=2592000; v="44,43,39,35"]
    Server: [UploadServer]
    X-GUploader-UploadID: [AEnB2UqT6y8KyZNCPyAaFeCj7I_ABIlwLJQMpltYzQ7D8blW4v3uKSlMT7dbNjFV0i_7ApzoR-i26ZtZ9kHkB7bI8n8ojgOnNA]
    Content-Length: [510]
    Date: [Sun, 05 Aug 2018 11:19:15 GMT]
    Content-Type: [text/plain]
response body:
    null

I've also tried using the value returned in the X-GUploader-UploadID header, but that causes a 500 error.

Can someone provide a working example of how to upload bytes to the Google Photos API?

Thank you!

Gauge answered 5/8, 2018 at 11:39 Comment(0)
S
2

I think you're just not looking at the Response content. The following works in Python, surely you can make it work for Java as well:

def upload_files(self, filepath, album_id):
    filename = os.path.basename(filepath)
    url = 'https://photoslibrary.googleapis.com/v1/uploads'
    authorization = 'Bearer ' + creds.access_token

    headers = {
        "Authorization": authorization,
        'Content-type': 'application/octet-stream',
        'X-Goog-Upload-File-Name': filename,
        'X-Goog-Upload-Protocol': 'raw',
    }
    with open(filepath, "rb") as image_file:
        response = requests.post(url, headers=headers, data=image_file)
        assert response.status_code == 200
        token = response.text  # !!!
    return service.mediaItems().batchCreate(body=dict(
        albumId=album_id,
        newMediaItems=[
            {"simpleMediaItem": {"uploadToken": token}}]
    )).execute()
Steck answered 27/8, 2018 at 11:13 Comment(3)
Any idea on how to make this work with react-native? I have a base64 encoded image, photoslibrary.googleapis... returns an uploadToken, when I use that to upload the image to an album, I am getting "NOT_IMAGE: There was an error while trying to create this media item."Iquique
@Iquique did you try with an image that is not base64 encoded?Vergievergil
@Vergievergil I dont remember my final solution, but like you suggest, I found a way to get the binary data that the google photos api requires.Iquique
P
1

You in fact do get a response body. If you look at your response

response: OK [200]
response headers:
    Alt-Svc: [quic=":443"; ma=2592000; v="44,43,39,35"]
    Server: [UploadServer]
    X-GUploader-UploadID: [AEnB2UqT6y8KyZNCPyAaFeCj7I_ABIlwLJQMpltYzQ7D8blW4v3uKSlMT7dbNjFV0i_7ApzoR-i26ZtZ9kHkB7bI8n8ojgOnNA]
    Content-Length: [510]
    Date: [Sun, 05 Aug 2018 11:19:15 GMT]
    Content-Type: [text/plain]
response body:
    null

there is the field Content-Length that indicates the length in bytes of the body, which is 510 in your case. Which method did you use to get this info? And what is your current implementation?

If you only tried to do the request e.g. via curl then I actually have no idea, why there is no response body, but then it wouldn't fit into the scope of the java tag anyways, so I'm assuming you parsed the response yourself in some self-written java code?

Because you didn't provide it, this is only speculation, but I'm assuming you missed something, when parsing the response.

Pennyworth answered 12/4, 2019 at 9:16 Comment(1)
do uploads need a response body?Vergievergil
P
1

This is working for me, the r.content returned in the below method is what contains the upload token which you will need to pass to the MediaItems:batchCreate API call in order the create the media in the user's library:

def upload(your_access_token, your_media_path):
item = open(your_media_path, 'rb').read()
url = 'https://photoslibrary.googleapis.com/v1/uploads'
headers = {
    'Authorization': 'Bearer ' + token,
    'Content-Type': 'application/octet-stream',
    'X-Goog-Upload-File-Name': 'image1.jpg',
    'X-Goog-Upload-Protocol': 'raw',
}

r = requests.post(url, data = item, headers = headers)
return r.content.decode('utf-8')
Payroll answered 26/4, 2019 at 22:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.