HOWTO access the Google Calendar API with Ruby

This guide will show you how to access the Google Calendar API (v3) with Ruby, using Google’s OAuth 2.0 flow for web applications and version 0.9 of the google-api-client gem—If you’ve been struggling to figure out how to move past version 0.8.2 this is for you!


Step 1: Setup your project

First you’ll need to sign in to the Google Developers Console and register your app:

You can find these pages under the “APIs & auth” menu item, and you can come back and tweak all these settings before you deploy to staging or production environments.

Step 2: Install the google-api-client gem

Add the google-api-client gem to your Gemfile:

gem 'google-api-client', '~> 0.9', require: 'google/apis/calendar_v3'

Then run bundle. The gem has a lot of dependencies, but will save you from having to write any low level HTTP client code to call the API.

Step 3: Obtain an authorization code

The first step in the OAuth 2.0 flow is to redirect the user to Google so they can sign in and consent to the access you are requesting.

If you’re using Rails your controller action might look something like this:

def redirect
  client = Signet::OAuth2::Client.new({
    client_id: ENV.fetch('GOOGLE_API_CLIENT_ID'),
    client_secret: ENV.fetch('GOOGLE_API_CLIENT_SECRET'),
    authorization_uri: 'https://accounts.google.com/o/oauth2/auth',
    scope: Google::Apis::CalendarV3::AUTH_CALENDAR_READONLY,
    redirect_uri: url_for(:action => :callback)
  })

  redirect_to client.authorization_uri.to_s
end

There’s a lot going on here, so let’s go through some of the details:

Step 4: Obtain an access token

The next step in the OAuth 2.0 flow is to handle the callback and exchange the temporary authorization code for an access token. If you’re using Rails your controller action might look something like this:

def callback
  client = Signet::OAuth2::Client.new({
    client_id: ENV.fetch('GOOGLE_API_CLIENT_ID'),
    client_secret: ENV.fetch('GOOGLE_API_CLIENT_SECRET'),
    token_credential_uri: 'https://accounts.google.com/o/oauth2/token',
    redirect_uri: url_for(:action => :callback),
    code: params[:code]
  })

  response = client.fetch_access_token!

  session[:access_token] = response['access_token']

  redirect_to url_for(:action => :calendars)
end

Initialization of the client object is similar to before, and includes the temporary authorization code from the request params.

The call to #fetch_access_token! exchanges the authorization code for an access token, which is then put into the session to persist it between requests.

Step 5: Call the Google Calendar API

Now that you have an access token you can call the Google Calendar API itself–finally!

The callback action in the previous step finishes by redirecting to a calendars action, which you can implement like this:

def calendars
  client = Signet::OAuth2::Client.new(access_token: session[:access_token])

  service = Google::Apis::CalendarV3::CalendarService.new

  service.authorization = client

  @calendar_list = service.list_calendar_lists
end

This time the client object is initialized with the access token from the session. The service object provides methods for making calls to the Calendar API. This example calls the CalendarList: list API method, which returns entries on the user’s calendar list. The API response is assigned to an instance variable so it can be accessed from the view.

You can then add in a basic view to list the calendar entries like this:

<ul>
<% @calendar_list.items.each do |calendar| %>
  <li><%= calendar.summary %></li>
<% end %>
</ul>

You should now be able to test the complete flow end-to-end by starting at the redirect action. If everything is configured correctly the callback action should fetch the access token and redirect to the calendars action to display a list of your calendars.

Things to consider

The examples above implement the “happy path”, and don’t handle errors or exceptions which you should code for in a production ready application. Some common failure scenarios you might want to implement:

The code examples above contain some duplication in setting up the signet client. To reduce this you can either use some of the classes included in the google-api-client gem (e.g. Google::APIClient::ClientSecrets and Google::APIClient::InstalledAppFlow), or you can refactor and reorganize it as you would any other code.

You might want to consider storing the tokens in some kind of datastore instead of the session, depending on the needs of your application.