GoogleCalendarAPI奮闘記

業務でGoogleCalendarAPIを使った時のメモ

# やりたかったこと

  • 対象アカウントのGoogleカレンダーから空いてる時間帯を抽出し、指定の時間帯に予定を入れる

イメージ

# 以下作業メモ

公式のドキュメントはこちら。

Railsを使っていたのでRubyのドキュメントを参考にした。

Ruby Quickstart  |  Calendar API  |  Google Developers

認証のためのキーが必要なのでGoogle Cloud Platformから取得する。

認証方法はどうやら以下三つがあるらしい。

  1. APIキー
  2. OAuthクライアントID
  3. サービスアカウント

今回はユーザーのデータにアクセスする必要はなく、Railsアプリからグーグルカレンダーへのアクセスなのでサービスアカウントを使うみたい。

OAuthにも色々あるらしく、このドキュメントに詳細説明がある。

Using OAuth 2.0 to Access Google APIs  |  Google Identity Platform

シーケンス図があるのがわかりやすい。性質を考えればわかるが、サービスアカウント以外は基本的に同意画面が開いてユーザー自身にID/PWを入力してもらうことになる。最初この辺の違いが全くわからなくてハマった。

ちなみにAPIキーを使う方法だとイベントの取得はできたが登録はできなかった。

イベントの取得

Events: list  |  Calendar API  |  Google Developers

→ 「Note: Authorization optional」と書いてある

イベントの登録

Events: insert  |  Calendar API  |  Google Developers

→ 「Note: Requires Authorization」と書いてある

Authorizationの詳細のドキュメントを見てみるとOAuth認証が必須だと書いてある。これを見逃していて当初APIキーを使って予定の登録をしようとしてハマった。取得ができるんだから登録もできるはずと思い込んでいた。

Authorizing Requests to the Google Calendar API  |  Google Developers

サービスアカウントの認証情報は以下の方法でダウンロードできる。

ただこれをどう使うかのサンプルがなかなか見つからなかった。

Ruby Quickstart  |  Calendar API  |  Google Developers

この公式のサンプルコードはコマンドラインで実行するものだったので少し違う。

色々調べていくと

googleapis/google-api-ruby-client: REST client for Google APIs

drive = Drive::DriveService.new
drive.authorization = ... # See Googleauth or Signet libraries

というコードを見つけた。 どうやら~~Searviceのインスタンスを生成してそのauthorizationに認証関連のインスタンスをいれてやれば上手く動きそうなことがわかった。authorizationに関してはGoogleauthやSignetを見ろと書いてある。

調べてみるとCalendarにもGoogle::Apis::CalendarV3::CalendarServiceというクラスがあることを確認した。

Class: Google::Apis::CalendarV3::CalendarService — Documentation for google/google-api-ruby-client (master)

なのでCalendarでもこのやり方でいけそう。

Googleauthとは何かを次に調べた。

https://github.com/googleapis/google-auth-library-ruby

この中にまさにサービスアカウントを使う場合のサンプルが書いてあった。

authorizer = Google::Auth::ServiceAccountCredentials.make_creds(
  json_key_io: File.open('/path/to/service_account_json_key.json'),
  scope: scope)
def initialize
  @calendar_service = Google::Apis::CalendarV3::CalendarService.new.tap { |cs| cs.authorization = authorizer }
end

def authorizer
  @authorizer ||= Google::Auth::ServiceAccountCredentials.make_creds(
    json_key_io: File.open('credentials.json'),
    scope: scope
  )
end

これでうまく取得と登録ができるようになった。

# その他はまったところ

# タイムゾーンの指定

APIの引数にDateTime型を指定する場合、タイムゾーンをしっかり指定してあげないと時間がずれる。具体的にはTime.zone.now.to_datetimeTime.current.to_datetimeにする必要がある。

# 定例イベントのスタート時間が正しく取得できない

毎週行うような定例イベントのスタート時間がなぜかずれる。タイムゾーンの指定もしてある。 これははっきり原因がわからないが、single_event: trueでリクエスト送らないといけないらしい。

公式のこの説明見ても読み取れなかった。

single_events (Boolean) (defaults to: nil) — Whether to expand recurring events into instances and only return single one- off events and instances of recurring events, but not the underlying recurring events themselves. Optional. The default is False.

https://www.rubydoc.info/github/google/google-api-ruby-client/Google/Apis/CalendarV3/CalendarService#insert_event-instance_method

参考記事

Google Calendar API と PHP で 予定の取得と追加をしてみるよ(準備編) | 株式会社LIG

Google Calendar API と PHP で 予定の取得と追加をしてみるよ(PHP編) | 株式会社LIG