業務でGoogleCalendarAPIを使った時のメモ
# やりたかったこと
- 対象アカウントのGoogleカレンダーから空いてる時間帯を抽出し、指定の時間帯に予定を入れる
イメージ
# 以下作業メモ
公式のドキュメントはこちら。
Railsを使っていたのでRubyのドキュメントを参考にした。
Ruby Quickstart | Calendar API | Google Developers
認証のためのキーが必要なのでGoogle Cloud Platformから取得する。
認証方法はどうやら以下三つがあるらしい。
- APIキー
- OAuthクライアントID
- サービスアカウント
今回はユーザーのデータにアクセスする必要はなく、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
というクラスがあることを確認した。
なので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_datetime
やTime.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.
参考記事