はじめに
カレンダーの開発を実施する上で、インターネットの標準仕様に合わせて作るのが良いですね。
カレンダーの標準仕様はRFC5545で定義されています。開発する上で必ず目を通す必要はありますが、RFC5545は抽象的な部分があり、いまいちピンとこない部分があります。RFC5545→実装はなかなか難しいので、今回はRFC5545を実装に落とし込んだGoogleCalendarを元に学んでいきます!
Google Calendarシリーズ
Google CalendarAPIを学ぶ(Step1:APIの仕様、リソースを理解する)
GoogleCalendar APIを学ぶ(Step2:TBL作成、データ挿入)
GoogleCalendar APIを学ぶ(Step3:カレンダーの取得APIを実装する)
GoogleCalendar APIを学ぶ(Step4:カレンダーに紐づくイベントの一覧取得APIを実装する)
Google Calendar API
Google Calendar APIの概要をつかみましょう。
→こんだけ書かれていてもよくわからないですね😅 1つづつ理解していきましょう。
まずは用語の意味と関係性を示していきます
用語の理解
| 要素 | 説明 |
|---|---|
| ユーザー | Google カレンダーを利用する主体。1アカウントにつき1つ。 |
| カレンダーリスト | ユーザーが左側ペインに登録しているカレンダーの一覧。表示・非表示や色・通知設定などユーザー固有のメタデータを管理。 |
| カレンダー | イベント(予定)を格納するコンテナ。タイムゾーン、説明文、デフォルトの通知設定などを保持。 |
| イベント | 単発予定または繰り返し予定の個別インスタンス。開始・終了時刻、参加者、リマインダーなどを含む。 |
| 設定 | ユーザー全体の環境設定(週の開始曜日、既定リマインダー方法など)。1ユーザーにつき1件。 |
| ACL | カレンダーへのアクセス権を表すルール(owner/writer/reader)。ユーザーやグループ単位で付与。 |
関係性
| 関係 | 意味 |
|---|---|
ユーザー → カレンダーリスト |
1 ユーザーが複数のカレンダーリストエントリを持つ |
カレンダーリスト → カレンダー |
1 エントリは 1 つのカレンダーを参照 |
カレンダー → イベント |
1 カレンダーに複数のイベントが属する |
ユーザー → 設定 |
ユーザーごとに 1 件の設定情報が紐づく(1:1) |
ユーザー -.-> ACL |
ユーザーやグループに ACL ルールが複数紐づく(点線) |
ACL -.-> カレンダー |
各 ACL ルールが対象カレンダーへのアクセス権を定義(点線) |
- 実線 (
-->) は 所有 や 1:N の構造的な関係を示します。 - 点線 (
-.->) は アクセス権付与 のような「強制ではないが関連する」関係を示します。
ふわっとした理解ができましたね。次はリソースごとに理解していこうと思います。
リソースの理解
カレンダーのリソース
{
"kind": "calendar#calendar", // リソース種別: カレンダーリソースを表す固定文字列
"etag": "\"XpAbC1234yz\"", // バージョン管理用タグ(例: 変更ごとに自動生成される ETag)
"id": "primary", // カレンダーID("primary" はメインカレンダー、セカンダリなら "xxx@group.calendar.google.com")
"summary": "Team Project Calendar", // カレンダー名(例: チーム用プロジェクトカレンダー)
"description": "カンファレンスや締め切りを共有するためのチーム用カレンダーです。",
// 説明文(例: 用途や対象を記載)
"location": "Tokyo Headquarters", // 所在地(フリーフォーム、例: 本社所在地)
"timeZone": "Asia/Tokyo", // IANA タイムゾーン名(例: Asia/Tokyo)
"conferenceProperties": {
"allowedConferenceSolutionTypes": [
"hangoutsMeet", // Google Meet を有効化
"eventHangout" // イベントハングアウト(旧 Hangouts)を有効化
]
}
}
| プロパティ | 型/値例 | 説明 |
|---|---|---|
| kind |
string"calendar#calendar"
|
リソース種別を示す固定文字列 |
| etag |
string"\"XpAbC1234yz\""
|
現バージョンを示すエンティティタグ(変更検出・楽観的排他制御用) |
| id |
string"primary"
|
カレンダーの一意識別子(主に API 呼び出し時のキー) |
| summary |
string"Team Project Calendar"
|
カレンダー名(タイトル) |
| description |
string"カンファレンスや締め切りを共有するチーム用カレンダー"
|
カレンダーの詳細説明 |
| location |
string"Tokyo Headquarters"
|
カレンダーの所在地情報(フリーフォーム) |
| timeZone |
string"Asia/Tokyo"
|
カレンダーのデフォルトタイムゾーン(IANA 名) |
| conferenceProperties | object |
会議リンク機能に関する設定オブジェクト |
| └─ allowedConferenceSolutionTypes |
string[]["hangoutsMeet","eventHangout"]
|
使用を許可する会議ソリューションの種類リスト |
カレンダーリストのリソース
{
"kind": "calendar#calendarListEntry", // リソース種別:カレンダーリストエントリ
"etag": "\"LmNoP5678qrs\"", // バージョン管理用タグ
"id": "team-shifts@example.com", // カレンダーID(グループカレンダーなど)
"summary": "Team Shifts", // カレンダーリスト上の表示名
"description": "部署の勤務シフトを管理するカレンダー", // カレンダーの詳細説明
"location": "Tokyo Office", // 場所
"timeZone": "Asia/Tokyo", // タイムゾーン
"summaryOverride": "My Shifts", // ユーザーが上書きしたカレンダー名
"colorId": "7", // 色ID(colorsリソース参照)
"backgroundColor": "#9ae2f1", // 背景色
"foregroundColor": "#000000", // 文字色
"hidden": false, // 非表示フラグ
"selected": true, // 左ペインで選択中かどうか
"accessRole": "writer", // 自分に付与された権限(owner/writer/reader/...)
"defaultReminders": [
{
"method": "popup", // リマインダー方法
"minutes": 30 // イベント開始30分前
}
],
"notificationSettings": {
"notifications": [
{
"type": "eventCreation", // イベント作成通知
"method": "email" // 通知方法
},
{
"type": "eventChange", // イベント変更通知
"method": "popup" // 通知方法
}
]
},
"primary": false, // プライマリカレンダーかどうか
"deleted": false, // リストエントリが削除済みかどうか
"conferenceProperties": {
"allowedConferenceSolutionTypes": [
"hangoutsMeet", // Google Meet
"eventHangout" // イベントハングアウト
]
}
}
設定
{
"kind": "calendar#setting", // リソース種別: 設定リソースを表す固定文字列 [oai_citation:0‡Google for Developers](https://developers.google.com/workspace/calendar/api/v3/reference/settings)
"etag": "\"ZmNoEnEtAg0123\"", // バージョン管理用タグ(例: 設定変更ごとに変わる ETag) [oai_citation:1‡Google for Developers](https://developers.google.com/workspace/calendar/api/v3/reference/settings)
"id": "timeZone", // 設定キー: ユーザーのタイムゾーンを示す設定 ID
"value": "Asia/Tokyo" // 設定値: IANA タイムゾーン名 [oai_citation:2‡Google for Developers](https://developers.google.com/workspace/calendar/api/v3/reference/settings?utm_source=chatgpt.com)
}
| プロパティ | 型/値例 | 説明 |
|---|---|---|
| kind |
string"calendar#setting"
|
リソース種別を示す固定文字列 |
| etag |
string"\"ZmNoEnEtAg0123\""
|
リソースのバージョンを表す ETag。変更検出や楽観的排他制御に利用 |
| id |
string"timeZone"
|
設定項目を識別するキー(例:autoAddHangouts、weekStart、timeZone) |
| value |
string"Asia/Tokyo"
|
設定値。設定 ID によって文字列/数値/JSON 形式などが異なる |
ACL
{
"kind": "calendar#aclRule", // リソース種別: ACLルール
"etag": "\"AbCdEf123456\"", // バージョン管理用ETag(変更ごとに変わるタグ)
"id": "rule_123abc", // このACLエントリの一意ID
"scope": {
"type": "user", // 対象タイプ: user (特定ユーザー)
"value": "alice@example.com" // 対象ユーザーのメールアドレス
},
"role": "writer" // 付与する権限: writer (読み書き可)
}
| プロパティ | 型/値例 | 説明 |
|---|---|---|
| kind |
string"calendar#aclRule"
|
リソース種別を示す固定文字列 |
| etag |
string"\"AbCdEf123456\""
|
リソースのバージョンを示す ETag |
| id |
string"rule_123abc"
|
この ACL ルールの一意識別子 |
| scope.type |
string"user"
|
ルール適用対象のタイプ(user/group/domain/default) |
| scope.value |
string"alice@example.com"
|
user/group/domain の場合の識別子 |
| role |
string"writer"
|
付与する権限レベル(owner/writer/reader/…) |
ACL Rule の scope.value 詳細
scope.value は scope.type に応じて以下のような形式・意味を持ちます。
| scope.type | value の形式 | 意味 | 例 |
|---|---|---|---|
| user | メールアドレス文字列 | 特定ユーザーを対象 | alice@example.com |
| group | Google グループのメール | 特定グループ(Google グループ)を対象 | dev-team@example.com |
| domain | ドメイン名(ホスト部のみ) | ドメイン内のすべてのユーザーを対象 | example.com |
| default | ―(省略または空文字) | 未認証ユーザーを含む全員に公開(公開権) | ※フィールド自体が返却されない |
-
user / group
- 値は実際に存在するユーザー/グループのメールアドレスである必要があります。
- グループは G Suite/Google Workspace のグループを指します。
-
domain
- 自社ドメイン全体にアクセスを許可したいときに使います。
- たとえば
example.comとすると@example.comユーザー全員が対象です。
-
default
- 認証不要でカレンダーを公開したい(全世界に公開)場合に利用。
-
valueフィールドは返却されず、scopeオブジェクトは{ "type": "default" }だけになります。
イベント
{
"kind": "calendar#event", // リソース種別
"etag": "\"abcd12345\"", // バージョン管理用 ETag
"id": "evt_12345", // イベント ID
"status": "confirmed", // 確定/仮予約/キャンセル
"htmlLink": "https://www.google.com/calendar/event?eid=evt_12345",
"created": "2025-05-17T10:00:00Z", // 作成日時
"updated": "2025-05-17T12:00:00Z", // 更新日時
"summary": "Project Kickoff", // タイトル
"description": "初回キックオフミーティング", // 詳細
"location": "オンライン", // 場所
"colorId": "6", // 色 ID
"creator": { // 作成者情報
"id": "user_123",
"email": "alice@example.com",
"displayName": "Alice",
"self": false
},
"organizer": { // 主催者情報
"email": "alice@example.com",
"displayName": "Alice",
"self": true
},
"start": { // 開始時刻
"dateTime": "2025-05-20T09:00:00Z",
"timeZone": "UTC"
},
"end": { // 終了時刻
"dateTime": "2025-05-20T10:00:00Z",
"timeZone": "UTC"
},
"recurrence": [ // 繰り返しルール
"RRULE:FREQ=WEEKLY;BYDAY=MO"
],
"recurringEventId": "evt_master_678", // シリーズイベントのマスター ID
"originalStartTime": { // 例外インスタンスの元開始時刻
"dateTime": "2025-05-20T09:00:00Z"
},
"transparency": "opaque", // ブロック状態
"visibility": "default", // 公開範囲
"iCalUID": "abcd12345@google.com", // iCal UID
"sequence": 2, // 更新シーケンス番号
"attendees": [ // 出席者一覧
{
"email": "bob@example.com",
"displayName": "Bob",
"responseStatus": "accepted",
"optional": false
}
],
"reminders": { // リマインダー設定
"useDefault": false,
"overrides": [
{
"method": "popup",
"minutes": 10
}
]
}
}
| プロパティ | 型/値例 | 説明 |
|---|---|---|
| kind |
string"calendar#event"
|
リソース種別を示す固定文字列 |
| etag |
string"\"abcd12345\""
|
リソースのバージョンを示す ETag(変更検出・楽観的排他制御用) |
| id |
string"evt_12345"
|
イベントの一意識別子 |
| status |
string"confirmed"
|
イベントの状態(confirmed/tentative/cancelled) |
| htmlLink |
string"https://www.google.com/calendar/event?eid=evt_12345"
|
ブラウザで開くイベント詳細ページの URL |
| created |
string"2025-05-17T10:00:00Z"
|
イベント作成日時 |
| updated |
string"2025-05-17T12:00:00Z"
|
最終更新日時 |
| summary |
string"Project Kickoff"
|
イベントタイトル |
| description |
string"初回キックオフミーティング"
|
イベント詳細 |
| location |
string"オンライン"
|
イベント開催場所 |
| colorId |
string"6"
|
イベント色の識別子(colors リソース参照) |
| creator |
object{email, displayName, self}
|
作成者情報(メール・表示名・自己フラグなど) |
| organizer |
object{email, displayName, self}
|
主催者情報(メール・表示名・自己フラグなど) |
| start |
object{dateTime:"2025-05-20T09:00:00Z", timeZone:"UTC"}
|
開始時刻情報(日時+タイムゾーン) |
| end |
object{dateTime:"2025-05-20T10:00:00Z", timeZone:"UTC"}
|
終了時刻情報(日時+タイムゾーン) |
| recurrence |
string[]["RRULE:FREQ=WEEKLY;BYDAY=MO"]
|
繰り返しルールの配列 |
| recurringEventId |
string"evt_master_678"
|
繰り返しマスターイベントの ID |
| originalStartTime |
object{dateTime:"2025-05-20T09:00:00Z"}
|
例外インスタンスの元の開始時刻 |
| transparency |
string"opaque"
|
ブロック状態(opaque=予定ブロック、transparent=空き扱い) |
| visibility |
string"default"
|
公開範囲(default/public/private/confidential) |
| iCalUID |
string"abcd12345@google.com"
|
iCalendar 標準の UID |
| sequence |
integer2
|
更新ごとのシーケンス番号 |
| attendees |
object[][{email,displayName,responseStatus,optional}]
|
出席者リスト(メール・表示名・応答状態・オプション参加など) |
| reminders |
object{useDefault:false,overrides:[{method:"popup",minutes:10}]}
|
リマインダー設定(既定利用フラグ+個別オーバーライド設定) |
イベントリソースの拡張フィールド解説
以下では、recurrence、recurringEventId、originalStartTime、iCalUID、transparency、visibility の6つのフィールドについて詳しく説明します。
1. recurrence
-
型:
string[] -
例:
["RRULE:FREQ=WEEKLY;BYDAY=MO,WE,FR"] -
説明:
iCalendar 標準の繰り返しルールを表す文字列の配列。-
RRULE:(必須)で繰り返しの頻度や曜日を指定 -
EXDATE:で除外日、RDATE:で追加日を指定可能
-
-
用途:
毎週○曜日や毎月○日などの繰り返し予定を定義し、events.instancesメソッドで個々のインスタンスを取得する
2. recurringEventId
-
型:
string -
例:
"evt_master_678" -
説明:
繰り返しシリーズのマスターイベント(元のイベント)のid。
このフィールドが存在する場合、そのイベントは例外インスタンス(時間変更やキャンセルされた回)であることを示します。 -
用途:
例外インスタンスをマスターイベントと紐づけて管理するために使用します。
3. originalStartTime
-
型:
object
{
"dateTime": "2025-05-20T09:00:00Z",
"timeZone": "UTC"
}
-
説明:
例外インスタンスの「元々の開始時刻」を保持するオブジェクトです。 -
用途:
変更前の予定日時を把握したいときに使用されます。UI での表示や履歴の記録にも有用です。
4. iCalUID
-
型:
string
"abcd12345@google.com"
-
説明:
iCalendar 標準仕様に基づく UID。Google Calendar がイベントを外部カレンダーと同期する際に使用されます。 -
用途:
Outlook や Apple カレンダーなどとのイベント同期の際に一貫性を保つために活用されます。
5. transparency
-
型:
string
"opaque" // 予定あり(ブロック)
"transparent" // 空き時間扱い
-
説明:
Free/Busy 情報におけるブロック状態の制御設定です。 -
用途:
会議のスケジュール候補を表示する際に、他の予定と重ならない時間帯を探すロジックに使用されます。
6. visibility
-
型:
string
"default" // カレンダー既定に従う
"public" // 誰でも詳細を閲覧可
"private" // 詳細を隠して「予定あり」のみ表示
"confidential" // より制限された公開レベル
-
説明:
イベントの公開レベルを制御するための設定です。 -
用途:
他ユーザーにどこまで情報を見せるか(または見せないか)を制御し、機密性を保ちつつ共有できます。
最後に
ここまででGoogle Calendarの仕様がわかってきました。次のStepでは、実際にTBLの設計をしていこうと思います






