September 25, 2014

Google Drive API: upload files to a folder using "Service Account"

The case

You have a server application which needs to upload some files to a specific folder in Google Drive which is owned by someone (e.g., by you).

Preface

I have spent lot of time, trying to figure out how to do it. It was a really big quest, besause:

  1. Google has tons of docs on their API.
  2. Those docs are really useless: lots of words without specifics.
  3. Docs have many cross-references which might point to nowhere or to some place which is out of date.
  4. It's hard to get links to some important places, e.g. to the list of available API scopes.
  5. Auth for non-humans is poorly documented and can be a pain.
  6. Your "Google account" and your "Service account" are quite different things, so they might seem to have different file storages, hence, this requires some work with permissions.

For example, docs for GitHub API are not big, but they clear and loud.

The real part

So, to start you will need to:

  1. Sign in to your Google account.
  2. Go to Google API Console.
  3. Create new project.
  4. Click to "APIs & auth" of the left side panel.
  5. Click "APIs", search for "Drive API" and enable it.
  6. ClicK "Credentials" and "Create new Client ID".
  7. Select "Service account" and create new Client ID.
  8. You will be automatically prompted to download your private key in 'PKCS12' format.
  9. Password for accessing it will be shown in pop-up. You may never need it, but it's better to put it to some secret place.
  10. Download that key and keep it private on your system.
  11. After that you will see "Client ID" and "Email address" for your application.
  12. Go to you Google Drive. Create some folder, and open "Sharing settings" for it.
  13. Add your service email to the list of allowed users and allow it to edit the contents of that folder.
  14. Remember folder ID somewhere.

NOTE: Sharing your folder with service account is just a special case. I'm not sure if it's fully secure to use service email, as it contains a significant part of Client ID. I think, it's ok, if you and only you can see the list of permissions.

You can store your files in the storage of your service account. You will need to read API docs for sharing and changing permissions to make files accessible even by you (I gave up at this point).


Be attentive while copying service email. Don't grab some extra whitespaces or new lines.


Enter the code

Now, you can write some code. Let's start from imports:

Here you can see 2 non-standard packages are used: 'apiclient' and 'oauth2client'. They are a part of 'google-api-python-client'. You can install it by running:

However, to make 'SignedJwtAssertionCredentials' work you will need to use PyOpenSSL, or PyCrypto 2.6 or later. You can choose any of them, but read notes below.

PyOpenSSL is might be already present in your system. If you need to use it inside your virtualenv (I hope, you need), then create a link:

You may use 'PyCrypto' directly, but it does not work with 'PKCS12' format. So, you will need to convert your private key to something understandable for 'PyCrypto':

This will convert 'PKCS12' to 'PEM', but that's not all: you will need to manually strip "Bag Attributes" and "Key Attributes" from it.

Let's define some constants for our example:

This is just an example. Never ever hardcode your API keys and secrets. Load them from environment, or from JSON file with secrets or wheresoever.

To use API for Google services you will need to get a 'service' object. This is done in same manner for all services:

File uploading consists of defining body, media body and invoking 'insert' method:

Let's try this out and upload some text file:

This will print an URL which can be used by humans for sharing. You may use 'pprint' to see all response:

Upset with having no full example? Don't worry, of course I'll share it with you: see full example.

5 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. good example any :) i have a similar code that work fine but not with big files any idea how to cover or fix that?

    ReplyDelete
  3. how can one create folders on the fly?

    ReplyDelete
  4. Is there a files collection? All I've seen in the documentation is object and bucket

    ReplyDelete