Search code examples
pythonpython-2.7restgoogle-drive-apihttplib2

Uploading file/metadata with httplib2 via Google Drive REST API


I'm attempting to write a simple CRUD library that interacts with Google Drive REST API[1] . I am able to Get and Delete from my drive but I am having issues with uploading a file.

I've come to the conclusion that httplib2 does not support multi-part uploads without writing my own logic for it so I have the methods split into two parts to upload the metadata and to upload the file content.

#ToDo: needs to be fixed to send binary data correctly, maybe set mimetype
#ToDo: add file metadata via second request (multipart not supported by httplib2)
def uploadDoc(self, filename, fileid=None):
    #ToDo: detect filetype
    data_type = 'image/png'
    # content_length //automatically detected
    url = "https://www.googleapis.com/upload/drive/v2/files"
    method = "POST"
    #replace file at this id if updating file
    if fileid:
        url += "/" + fileid
        method = "PUT"

    headers = {'Authorization' : 'Bearer ' + self.getTokenFromFile(), 'Content-type' : data_type}
    post_data = {'uploadType':'media',
                'file' :self.load_binary(filename)}

    (resp, content) = self.http.request(url,
                            method = method,
                            body = urlencode(post_data),
                            headers = headers)

    print content

#ToDo: metadata not being set, including content-type in header returns 400 status
def uploadFileMeta(self, filename, fileid=None, description=""):
    url = self.drive_api_url + "/files" 
    method = "POST"
    #replace file metadata at this id if updating file
    if fileid:
        url += "/" + fileid
        method = "PUT"

    headers = {'Authorization' : 'Bearer ' + self.getTokenFromFile()}
    post_data = {"title" : filename,
                "description": description}

    (resp, content) = self.http.request(url,
                            method = method,
                            body = urlencode(post_data),
                            headers = headers)

    print resp
    print content

#updating a specific doc will require the fileid
def updateFileMeta(self, fileid, filename, description=""):
    uploadFileMeta(fileid, filename, description)

def reuploadFile(self, fileid, filename):
    uploadDoc(filename, fileid)

def load_binary(self, filename):
    with open(filename, 'rb') as f:
        return f.read()

When I attempt to set title or description, the title is set as "Untitled" and the description doesn't show in the returned JSON at all. It's as if I'm not sending them correctly to the server.

My other issue is uploading a binary file. I believe I am either reading the file or encoding it incorrectly.

Any advice would be appreciated. I've been scratching my head for weeks on this.

Thanks!

EDIT: Clarification (TLDR): A document is created with title: "Untitled" and no description. Am I formatting the body or headers incorrectly for the uploadMeta function?


Solution

  • I needed to send json in my request as Gerardo suggested for the metadata.

    body = json.dumps(post_data)
    

    This does not work for sending the file content though. Still scratching my head on how to send the file.

    EDIT: I switched to using Requests to make the http requests and have managed to upload docs and metadata at the same time using the solution from this exchange.