Hangouts Chat Botのメッセージ仕様とかまとめ

# はじめに

Hangouts Chat Botをメッセージの仕様やイベントの仕様についてまとめた自分用メモ
**2018/08/21時点の内容です。**

# Hangouts Chat イベントフォーマット

Hangouts ChatでBotに対してユーザーが何かしらのアクションを起こしイベントが発生した際に
Botに送られるJSONペイロードは以下の図のようになっています。
必ずしも図のような形で送られる訳では無く、イベントによって要素がないものもあります。

![bot-event-json-diagram.png](https://qiita-image-store.s3.amazonaws.com/0/199859/dfc366a1-d07d-e5fe-e2a7-70a91500cd4e.png)
[Events formts](https://developers.google.com/hangouts/chat/reference/message-formats/events)より引用

## 各要素について

### 共通要素

どのイベントの場合でも送られてくる要素。

|要素名|タイプ|説明|
|----------|------|----------------------|
|type      |String|イベントの種類         |
|eventTime |String|イベントの発生時刻(UTC)|
|token     |String|確認トークンの値       |

確認トークンはBotの公開設定の際に自動で振られる値。この値が送られることでHangoutsChatから送信されたことを確認出来る。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/199859/11cb0a33-6ddf-fc8f-cdfa-74774c339889.png)

### 個別要素

|要素名|タイプ|説明|要素が送信されるイベント|
|---------------------|------------------|--------------------|---| 
|message              |Message|イベントの内容|MESSAGE, ADDED_TO_SPACE|
|space                |Space|イベントを発生させたスペース情報(DM, チャットルーム)|MESSAGE, ADDED_TO_SPACE, REMOVED_FROM_SPACE|
|user                 |User|イベントを発生させたユーザー情報|MESSAGE, ADDED_TO_SPACE, REMOVED_FROM_SPACE|
|thread               |Thread|messageが属するスレッド|MESSAGE|

いまいち意味が分かりませんがこんなもんだと思っていてください。
実際のJSONを見るとなるほどと結構思います。

## イベントについて

ユーザーがBotに対して起こしたアクションに対して発生するイベントは以下の通り。

- ADDED_TO_SPACE
- REMOVED_FROM_SPACE
- MESSAGE
- CARD_CLICKED

### ADDED_TO_SPACE

ユーザーがBotをダイレクトメッセージまたはチャットルームに追加した場合に発生するイベント。
ウェルカムメッセージやBotの使い方などを返信するといいかと。

```json:JSONの例
{
  "type": "ADDED_TO_SPACE",
  "eventTime": "2017-03-02T19:02:59.910959Z",
  "space": {
    "name": "spaces/AAAAAAAAAAA",
    "displayName": "Chuck Norris Discussion Room"
    "type": "ROOM"
  },
  "user": {
    "name": "users/12345678901234567890",
    "displayName": "Chuck Norris",
    "avatarUrl": "https://lh3.googleusercontent.com/.../photo.jpg",
    "email": "chuck@example.com"
  }
}
```

### REMOVED_FROM_SPACE

ユーザーがBotをダイレクトメッセージまたはチャットルームから削除した場合に発生するイベント。
BOTを削除しているのでメッセージを送ることは出来ない。
ユーザー情報を保持とかしているなら、削除処理とかを実装すると不要な情報を持ち続けるとか無くなるかなと。
何も情報を保持していないのなら何も実装する必要は無いと思います。

```json:JSONの例
{
  "type": "REMOVED_FROM_SPACE",
  "eventTime": "2017-03-02T19:02:59.910959Z",
  "space": {
    "name": "spaces/AAAAAAAAAAA",
    "type": "DM"
  },
  "user": {
    "name": "users/12345678901234567890",
    "displayName": "Chuck Norris",
    "avatarUrl": "https://lh3.googleusercontent.com/.../photo.jpg",
    "email": "chuck@example.com"
  }
}
```

### MESSAGE

Botにメッセージが送信された場合に発生するイベント。
Bot自信のメッセージや他のBotのメッセージの場合は発生しない。
基本的にはMESSAGEイベントに対して何かしらのレスポンスを返すのがBotのメイン。

```json:JSONの例
{
  "type": "MESSAGE",
  "eventTime": "2017-03-02T19:02:59.910959Z",
  "space": {
    "name": "spaces/AAAAAAAAAAA",
    "displayName": "Chuck Norris Discussion Room",
    "type": "ROOM"
  },
  "message": {
    "name": "spaces/AAAAAAAAAAA/messages/CCCCCCCCCCC",
    "sender": {
      "name": "users/12345678901234567890",
      "displayName": "Chuck Norris",
      "avatarUrl": "https://lh3.googleusercontent.com/.../photo.jpg",
      "email": "chuck@example.com"
    },
    "createTime": "2017-03-02T19:02:59.910959Z",
    "text": "@TestBot Violence is my last option.",
    "argumentText": " Violence is my last option.",
    "thread": {
      "name": "spaces/AAAAAAAAAAA/threads/BBBBBBBBBBB"
    },
    "annotations": [
      {
        "length": 8,
        "startIndex": 0,
        "userMention": {
          "type": "MENTION",
          "user": {
            "avatarUrl": "https://.../avatar.png",
            "displayName": "TestBot",
            "name": "users/1234567890987654321",
            "type": "BOT"
          }
        },
        "type": "USER_MENTION"
      }
    ],
  },
  "user": {
    "name": "users/12345678901234567890",
    "displayName": "Chuck Norris",
    "avatarUrl": "https://lh3.googleusercontent.com/.../photo.jpg",
    "email": "chuck@example.com"
  }
}
```

### CARD_CLICKED

Botがユーザーに発信したカード型メッセージをユーザーがクリックした場合に発生するイベント。

```json:JSONの例
{
  "type": "CARD_CLICKED",
  "eventTime": "2018-08-17T04:13:28.921183Z",
  "token": "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789012345678",
  "message": {
    "name": "spaces/AAAAAAAAAAA/messages/BBBBBBBBBBB.BBBBBBBBBBB",
    "sender": {
      "name": "users/12345678901234567890",
      "type": "BOT"
    },
    "createTime": "2018-08-17T04:13:28.921183Z",
    "cards": [
      {
        ユーザーがクリックしたカード型メッセージの内容
      }
    ],
    "thread": {
      "name": "spaces/AAAAAAAAAAA/threads/CCCCCCCCCCC",
      "retentionSettings": {
        "state": "PERMANENT"
      }
    },
    "space": {
      "name": "spaces/AAAAAAAAAAA",
      "type": "DM"
    }
  },
  "user": {
    "name": "users/104633399607547558876",
    "displayName": "Chuck Norris",
    "avatarUrl": "https://lh3.googleusercontent.com/.../photo.jpg",
    "email": "chuck@example.com",
    "type": "HUMAN"
  },
  "space": {
    "name": "spaces/AAAAAAAAAAA",
    "type": "DM"
  },
  "action": {
    "actionMethodName": "action01",
    "parameters": [
      {
        "key": "time",
        "value": "1 day"
      },
      {
        "key": "id",
        "value": "123456"
      }
    ]
  }
}
```

# Hangouts Chat メッセージフォーマット

Hangouts ChatでBotがユーザーに発信出来るメッセージの種類は以下の通り。

- Simple text messages
- Card messages

## Simple text messages

ユーザーが入力するようなテキストメッセージを発信するためのフォーマット。
以下のようなメッセージを発信出来る。

- テキストメッセージ
- 書式付きテキストメッセージ
- ハイパーリンク付きテキストメッセージ
- 特定ユーザーへのメンション付きメッセージ
- 全てのユーザーへのメンション付きメッセージ

### テキストメッセージ

何の変哲も無いテキストメッセージ。

```json:フォーマット
{
  "text": "テキストメッセージですよ。"
}
```

出力結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/199859/54ee4722-8290-6a25-cac2-8427e280f341.png)

### 書式付きテキストメッセージ

テキストメッセージに書式を設定したメッセージ。
以下の書式を設定出来る。

- Bold(太字)
- Italic(イタリック体)
- Strikethrough(打ち消し線)
- Monospace
- Monospace block

#### Bold

Boldを設定したい文字列を*(アスタリスク)で囲む。

```json:フォーマット
{
  "text": "*テキストメッセージですよ。*"
}
```

出力結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/199859/30cff8e8-9239-a5e8-8046-ce1d94f6cc95.png)

#### Italic

Italicを設定したい文字列を_(アンダースコア)で囲む。

```json:フォーマット
{
    "text": "_Text Message !!_"
}
```

出力結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/199859/27b67d47-5f98-0dd2-3d5f-1efeb655d228.png)

フォントによってはItalic体にならないと思われます。

#### Strikethrough

Strikethroughを設定したい文字列を~(チルダ)で囲む。

```json:フォーマット
{
  "text": "~テキストメッセージですよ。~"
}
```

出力結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/199859/7cfd2f4e-09fa-216a-8bcc-1e2be523469c.png)

#### Monospace

Monospaceを設定したい文字列を`(バッククォート)で囲む。

```json:フォーマット
{
  "text": "`テキストメッセージですよ。`"
}
```

出力結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/199859/c57ea2cf-5b3b-6dc5-3a5c-af75dae9a8fe.png)

#### Monospace block

Monospace blockを設定したい文字列を`(バッククォート)3個で囲む。

```json:フォーマット
{
  "text": "```テキストメッセージですよ1。\r\nテキストメッセージですよ2。\r\nテキストメッセージですよ3。```"
}
```

出力結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/199859/5ee5aea7-25ff-9d02-0784-25e987410d56.png)

### ハイパーリンク付きテキストメッセージ

ハイパーリンク付きのテキストメッセージ。
代替テキストを設定することも可能。

#### 代替テキスト設定無し

テキストメッセージとしてURLを記載すると自動でハイパーリンクにしてくれます。

```json:フォーマット
{
  "text": "ハイパーリンクですよ。https://qiita.com/"
}
```

出力結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/199859/67cd94fc-b3a6-f6b3-6580-72f23e231428.png)
出力結果にはよくあるサムネイルっぽいものが表示されます。

#### 代替テキスト設定有り

代替テキストを設定する場合は"<>"(不等号)で囲い、URLの後に"|"(パイプ)入力後代替テキストを設定する。

```json:フォーマット
{
  "text": "ハイパーリンクですよ。<https://qiita.com/|キータ>"
}
```

出力結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/199859/a80c9457-dc83-38a9-a966-4e77b5775aee.png)
代替テキストを設定するとサムネイルっぽいものは表示されないようです。

### 特定ユーザーへのメンション付きメッセージ

特定のユーザーに対してメンション付きのテキストメッセージ。
ダイレクトメッセージでやりとりしている場合は、あまり意味は無いがチャットルームにBotを導入した場合は便利なのかと。
メンションのフォーマットは"<>"(不等号)で囲い、**users** + "/"(スラッシュ) + USER_IDを設定する。
USER_IDはユーザーからメッセージが送られた際に、一緒に送られてくるものを使用する。

```
<users / USER_ID >
```

```json:フォーマット
{
  "text": "メンション付きメッセージですよ。<users/123456789012345678901>"
}
```

出力結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/199859/c7a133e4-721c-8a95-4f86-8be9b2a8fb21.png)

### 全てのユーザーへのメンション付きメッセージ

全てのユーザーへのメンション付きのテキストメッセージ
チャットルームで全体に通知したい場合などに便利なのかと。
メンションのフォーマットは"<>"(不等号)で囲い、**users** + "/"(スラッシュ) + "all"を設定する。

```json:フォーマット
{
  "text": "メンション付きメッセージですよ。<users/all>"
}
```

出力結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/199859/132901ac-ea48-91fd-0f23-05620e614ba4.png)

## Card messages

以下の画像のようなカード型メッセージを発信するためのフォーマット。

![pizzabot-card.png](https://qiita-image-store.s3.amazonaws.com/0/199859/cfaf7f17-8c14-9ec7-78f4-47a0e60074ce.png)
[Full example: Pizza Bot](https://developers.google.com/hangouts/chat/reference/message-formats/cards#full_example_pizza_bot)から引用

カード型メッセージは以下の要素から成り立つ。

- Headers
- Sections & Widgets

### Headers

カード型メッセージのヘッダーを定義する。
以下の要素を設定出来る。

- title - カード型メッセージのタイトル
- subtitle - カード型メッセージのサブタイトル
- imageUrl - ヘッダに表示されるアイコンのURL
- ImageStyle - アイコンの形状を指定(IMAGE or AVATAR)。IMAGEだと正方形、AVATARだと円形となる。

```json:フォーマット
  {
    "cards": [
      {
        "header": {
          "title": "カード型ヘッダータイトル",
          "subtitle": "カード型ヘッダーサブタイトル",
          "imageUrl": "https://goo.gl/aeDtrS",
          "imageStyle": "IMAGE"
        },
      }
    ]
  }
```

出力結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/199859/fe37d372-6e6d-675f-e68c-c187624cc116.png)

### Sections & Widgets

カード内に縦方向に追加されるレイアウトを定義する。
セクションの中にウィジェットが含まれる形になり、ウィジェットには以下の種類がある。

- TextParagraph Widget
- KeyValue Widget
- Image Widget
- Buttons Widget

#### TextParagraph Widget

TextParagraph Widgetはテキストを表示するウィジェット。
書式を設定することが出来るが、Simple text messagesの書式付きテキストメッセージと違い、
HTMLタグを使用して書式を設定する。
使用出来る書式は以下の通り。

- Bold \<b>タグ
- Italic \<i>タグ
- Underline \<u>タグ
- Strikethrough \<strike>タグ
- Font Color \<font color="">タグ
- Hyperlink \<a href="">タグ
- Line Break \<br>タグ

HTMLタグなので特に説明はしません。

```json:フォーマット
  {
    "cards": [
      {
        "header": {
          "title": "カード型ヘッダータイトル",
          "subtitle": "カード型ヘッダーサブタイトル",
          "imageUrl": "https://goo.gl/aeDtrS",
          "imageStyle": "AVATAR"
        },
        "sections": [
          {
            "widgets": [
              {
                "textParagraph": {
                  "text": "<b>Roses</b> <u>are</u> <font color=\"#ff0000\">red</font>,<br><i>Violets</i> <strike>are</strike> <font color=\"#0000ff\">blue</font>"
                }
              }
            ]
          },
        ]
      }
    ]
  }
```

出力結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/199859/93d49b59-86b8-4f16-1f3e-fbebe746d46b.png)

#### KeyValue Widget

ラベル(topLabel, bottomLabel)と値(content)の組み合わせで表示するウィジェット。
値の表示だけではなくonClickでリンクを開くなども出来る。
またアイコンを設定することも出来、URLで画像を指定するだけでは無く[ビルトインアイコン](https://developers.google.com/hangouts/chat/reference/message-formats/cards#builtinicons)も用意されている。

```json:フォーマット
  {
    "cards": [
      {
        "sections": [
          {
            "widgets": [
              {
                "keyValue": {
                  "topLabel": "Order No.",
                  "content": "1234567890",
                  "contentMultiline": "false",
                  "bottomLabel": "Delayed",
                  "onClick": {
                     "openLink": {
                      "url": "https://example.com/"
                     }
                   },
                  "icon": "TRAIN",
                 }
              }
            ]
          }
        ]
      }
    ]
  }
```

出力結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/199859/9ea7873b-13c7-30d2-41a7-8c9acdae9c22.png)

#### Image widget

画像を表示するウィジェット。
画像のURLを指定するとウィジェットの幅最大に表示するらしいんですが、
画像によっては表示されたりされなかったり…。
画像の表示だけではなくonClickでリンクを開くなども出来る。

```json:フォーマット
{
  "cards": [
    {
      "sections": [
        {
          "widgets": [
            {
              "image": {
                "imageUrl": "https://example.com/kitten.png",
                "onClick": {
                  "openLink": {
                    "url": "https://example.com/"
                  }
                }
              }
            }
          ]
        }
      ]
    }
  ]
}
```

出力結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/199859/b34bbec3-187a-4dac-792d-69de6f593924.png)

#### Buttons Widget

ボタンを表示するウィジェット。
テキストボタンとイメージボタンの2種類から指定出来る。
ボタンを押した後にリンクを開いたり、BotにCARD_CLICKイベントを送ったりすることが出来る。

```json:フォーマット
{
  "cards": [
    {
      "sections": [
        {
          "widgets": [
            {
              "buttons": [
                {
                  "imageButton": {
                    "icon": "AIRPLANE",
                    "onClick": {
                      "openLink": {
                        "url": "https://example.com/"
                      }
                    }
                  }
                },
                {
                  "imageButton": {
                    "icon": "EMAIL",
                    "onClick": {
                      "openLink": {
                        "url": "mailto:me@example.com"
                      }
                    }
                  }
                },
                {
                  "textButton": {
                    "text": "VISIT WEBSITE",
                    "onClick": {
                      "openLink": {
                        "url": "https://example.com/"
                      }
                    }
                  }
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}
```

出力結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/199859/65525854-4b74-f2fb-816e-47777bd2cc58.png)

# まとめ

- とりあえずこの内容分かっていればHangouts Chatで簡単なBotが作れるはず。