[Google Forms API(V1)] JavaでGoolgeフォームの変更監視を登録・更新・停止する

Gmail API v1（Java）を使用して、
Goolgeフォームの変更監視を登録・更新・停止する方法
についてご紹介します。

:::note info
APIを利用する環境の準備から始める場合や、コードを実行する際は、
[⧉[Google Forms API(V1)] JavaでForms APIを使う](https://qiita.com/doran/items/6a25c15309f442c4d679)
を参照ください。
:::

|No||目次|
|---|---|---|
|1||[プッシュ通知を登録](#1-プッシュ通知を登録)|
||1|[スコープ](#11-スコープ)|
||2|[実行](#12-実行)|
||3|[レスポンスの内容](#13-レスポンスの内容)|
|2||[プッシュ通知を更新](#2-プッシュ通知を更新)|
||1|[スコープ](#21-スコープ)|
||2|[実行](#22-実行)|
||3|[レスポンスの内容](#23-レスポンスの内容)|
|3||[プッシュ通知を停止](#3-プッシュ通知を停止)|
||1|[スコープ](#31-スコープ)|
||2|[実行](#32-実行)|
||3|[レスポンスの内容](#43-レスポンスの内容)|
|4||[プッシュ通知の内容](#4-プッシュ通知の内容)|
||1|[変更通知の受信](#41-変更通知の受信)|
||2|[変更内容の取得](#42-変更内容の取得)|

## 1. プッシュ通知を登録
プッシュ通知を登録します。
既に登録済みの場合は例外となります。

### 1.1. スコープ
このAPIを実行するには、以下のいずれかのスコープを指定してください。
```
FormsScopes.DRIVE
FormsScopes.DRIVE_FILE
FormsScopes.DRIVE_READONLY
FormsScopes.FORMS_BODY
FormsScopes.FORMS_BODY_READONLY
FormsScopes.FORMS_RESPONSES_READONLY
```
[⧉[Google Forms API(V1)] JavaでForms APIを使う(2.2 Gmailインスタンスを取得)](https://qiita.com/doran/items/6a25c15309f442c4d679#22-formsインスタンスを取得)
でスコープを指定してください。

### 1.2. 実行
```java
public static void main(String[] args) throws Exception{
    Forms forms = getForms();
    FormsOperations op = forms.forms();
    FormsOperations.Watches watches = op.watches();
    
    CreateWatchRequest content = new CreateWatchRequest();
    Watch watch = new Watch();
    watch.setTarget(new WatchTarget().setTopic(new CloudPubsubTopic().setTopicName("トピック名")));
    watch.setEventType("SCHEMA");
    content.setWatch(watch);
    FormsOperations.Watches.Create create = watches.create("フォームID", content);
    
    Watch res = create.execute();
    System.out.println(res);
}
```
#### 1.2.1. HTTPリクエスト
POST:　https:\//forms.googleapis.com/v1/forms/{フォームID}/watches
が実行されます。

#### 1.2.2. クエリパラメータ
クエリパラメータはありません。

#### 1.2.3. リクエストボディ
CreateWatchRequestのsetメソッドにより、リクエストボディを追加できます。

|メソッド|引数|説明|
|---|---|---|
|setWatch|[Watch](#watchset)|【必須】watchオブジェクト|
|setWatchId|String|ウォッチID<br>4〜63文字（省略時は自動生成）|

#### Watch(set)
|メソッド|引数|説明|
|---|---|---|
|setTarget|[WatchTarget](#watchtargetset)|【必須】通知の送信先|
|setEventType|[EventType(enum)](#eventtype)|【必須】監視するイベントタイプ|

#### WatchTarget(set)
|メソッド|引数|説明|
|---|---|---|
|setTopic|[CloudPubsubTopic](#cloudpubsubtopicset)|【必須】Pub/Subの設定|

#### CloudPubsubTopic(set)
|メソッド|引数|説明|
|---|---|---|
|setTopicName|String|【必須】Pub/Subのトピック名|

#### EventType
|定義値|説明|
|---|---|
|EVENT_TYPE_UNSPECIFIED|未指定|
|SCHEMA|コンテンツ設定の変更を通知|
|RESPONSES|フォームの回答が送信されると通知|

### 1.3. レスポンスの内容
#### Watch

|メソッド|戻り値|説明|
|---|---|---|
|getId|String|ウォッチID|
|getTarget|[WatchTarget](#watchtarget)|通知の送信先|
|getEventType|[EventType(enum)](#eventtype)|監視するイベントタイプ|
|getCreateTime|String|作成された時点のタイムスタンプ|
|getExpireTime|String|有効期限を示すタイムスタンプ|
|getErrorType|[ErrorType(enum)](#errortype)|試行された配信に対する最新のエラータイプ|
|getState|[State(enum)](#state)|ウォッチの現在の状態|

#### WatchTarget
|メソッド|引数|説明|
|---|---|---|
|getTopic|[CloudPubsubTopic](#cloudpubsubtopic)|Pub/Subの設定|

#### CloudPubsubTopic
|メソッド|引数|説明|
|---|---|---|
|getTopicName|String|Pub/Subのトピック名|

#### ErrorType
|定義値|説明|
|---|---|
|ERROR_TYPE_UNSPECIFIED|未指定|
|PROJECT_NOT_AUTHORIZED|監視対象フォームへのアクセス権がない|
|NO_USER_ACCESS|監視対象フォームにアクセスできなくなった|
|OTHER_ERRORS|別のタイプのエラー|

#### State
|定義値|説明|
|---|---|
|STATE_UNSPECIFIED|未指定|
|ACTIVE|アクティブ|
|SUSPENDED|停止中(解決可能なエラー発生中)|

## 2. プッシュ通知を更新
プッシュ通知の期限を７日間更新します。

[1. プッシュ通知を登録(Watch)](#watch)のexpireTime(有効期限)が更新されます。

### 2.1. スコープ
このAPIを実行するには、以下のいずれかのスコープを指定してください。
```
FormsScopes.DRIVE
FormsScopes.DRIVE_FILE
FormsScopes.DRIVE_READONLY
FormsScopes.FORMS_BODY
FormsScopes.FORMS_BODY_READONLY
FormsScopes.FORMS_RESPONSES_READONLY
```
[⧉[Google Forms API(V1)] JavaでForms APIを使う(2.2 Gmailインスタンスを取得)](https://qiita.com/doran/items/6a25c15309f442c4d679#22-formsインスタンスを取得)
でスコープを指定してください。

### 2.2. 実行
RenewWatchRequestは空のインスタンスを渡していますが、
NULLでもリクエストは通るようです。
```java
public static void main(String[] args) throws Exception{
    Forms forms = getForms();
    FormsOperations op = forms.forms();
    FormsOperations.Watches watches = op.watches();
    
    RenewWatchRequest content = new RenewWatchRequest();
    FormsOperations.Watches.Renew renew = watches.renew("フォームID","ウォッチID",content);
    
    Watch res = renew.execute();
    System.out.println(res);
}
```
#### 2.2.1. HTTPリクエスト
POST:　https:\//forms.googleapis.com/v1/forms/{フォームID}/watches/{ウォッチID}:renew
が実行されます。

#### 2.2.2. クエリパラメータ
クエリパラメータはありません。

#### 2.2.3. リクエストボディ
リクエストボディはありません。

### 2.3. レスポンスの内容
#### Watch
[1. プッシュ通知を登録(Watch)](#watch)と同じです。

## 3. プッシュ通知を停止
プッシュ通知を停止します。

### 3.1. スコープ
このAPIを実行するには、以下のいずれかのスコープを指定してください。
```
FormsScopes.DRIVE
FormsScopes.DRIVE_FILE
FormsScopes.DRIVE_READONLY
FormsScopes.FORMS_BODY
FormsScopes.FORMS_BODY_READONLY
FormsScopes.FORMS_RESPONSES_READONLY
```
[⧉[Google Forms API(V1)] JavaでForms APIを使う(2.2 Gmailインスタンスを取得)](https://qiita.com/doran/items/6a25c15309f442c4d679#22-formsインスタンスを取得)
でスコープを指定してください。

### 3.2. 実行
```java
public static void main(String[] args) throws Exception{
    Forms forms = getForms();
    FormsOperations op = forms.forms();
    
    FormsOperations.Watches watches = op.watches();
    FormsOperations.Watches.Delete delete = watches.delete("フォームID","ウォッチID");
    
    delete.execute();
}
```
#### 3.2.1. HTTPリクエスト
DELETE:　https:\//forms.googleapis.com/v1/forms/{フォームID}/watches/{ウォッチID}
が実行されます。

#### 3.2.2. クエリパラメータ
クエリパラメータはありません。

#### 3.2.3. リクエストボディ
リクエストボディはありません。

### 3.3. レスポンスの内容
レスポンスはありません。

## 4. プッシュ通知の内容
プッシュ通知は、Google PUB/SUBを使用して受信します。
PUB/SUBからPUSH先にURIを指定しますが、
今回はプッシュ通知の内容を見るだけなのでCloud Functionsを使用します。

Pub/SubとCloud Functionsを使用したメッセージの受信する方法は
[⧉[Pub/Sub - Cloud Functions] Google Cloud APIからの通知を受け取る](https://qiita.com/doran/items/343dac28c46143d61917)
を参照ください。

Forms APIからの通知を受信するには、トピックの権限に下記を追加してください。
追加方法は、上記記事の[⧉1.3. 権限の設定](https://qiita.com/doran/items/343dac28c46143d61917#13-権限の設定)をご覧ください。
|設定|設定値|
|---|---|
|プリンシバル|`forms-notifications@system.gserviceaccount.com`|
|ロール|`Pub/Sub パブリッシャー`|

#### 4.1. 変更通知の受信
プッシュ通知で次のフィールドが取得できます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/114621/3c38dda5-53df-b8fe-b0be-e5ef286c687a.png">

|フィールド|説明|実際に返ってきた値|
|---|---|---|
|eventType|イベントタイプ|SCHEMA|
|formId|フォームID|1zdIyqHiK5_UFJ-Cq7lqohNdoK01MpEnPenyIKFXlwno|
|watchId|ウォッチID|adcaf088-b870-445d-a4e0-09a272df9632|

#### 4.2. 変更内容の取得
何がどう変更されたかを取得するAPIは用意されていないようです。

なので、何かしら変更があった！ぐらいしかわからないみたい。。。

<br>
<br>
おしまい。。