Google Chat アプリでのやり取りの受信と返信

このページでは、Google Chat アプリでユーザー操作(Google Chat アプリ操作イベント)を受信して応答する方法について説明します。

Google Chat アプリのインタラクション イベントは、ユーザーが Chat アプリを呼び出したり操作したりするために行うアクション(Chat アプリの @メンション、スペースへの追加など)を表します。ユーザーが Chat アプリを操作すると、Google Chat から Chat アプリにインタラクション イベントが送信されます。Chat アプリは、このイベントを使用してインタラクションを処理し、レスポンスを作成できます。

たとえば、Chat アプリはインタラクション イベントを使用して次のことができます。

インタラクション イベントの例 Chat アプリからの一般的なレスポンス
ユーザーは、名前リンクを付けるか、スラッシュ コマンドを使用することで、Chat アプリを呼び出します。 Chat アプリは、メッセージの内容を処理してメッセージを作成します。たとえば、Chat アプリは /about コマンドに対して、Chat アプリが実行できるタスクを説明するメッセージを返します。
ユーザーがスペースに Chat アプリを追加します。 Chat アプリから、アプリの機能とスペース内のユーザーによる操作方法を説明するオンボーディング メッセージが送信されます。
ユーザーがスペースから Chat アプリを削除した場合。 Chat アプリは、そのスペース用に構成されたすべての受信通知(Webhook の削除など)を削除し、内部ストレージをすべてクリアします。
Chat アプリから送信されたカードまたはダイアログのボタンをユーザーがクリックする。 Chat アプリは、ユーザーが送信したデータを処理して保存するか、別のカードまたはダイアログを返します。

ユーザー インタラクションのタイプごとに、Google Chat から送信されるインタラクション イベントのタイプが異なります。たとえば、Google Chat では、ユーザーがメッセージ内で Chat アプリを呼び出すあらゆるインタラクションにイベントタイプ MESSAGE が使用されます。詳しくは、Google Chat アプリ操作イベントの種類をご覧ください。

このページでは、次の操作を行う方法について説明します。

  • イベントを受信するように Chat アプリを構成します。
  • インフラストラクチャ上でインタラクション イベントを処理します。
  • 必要に応じて、インタラクション イベントに応答します。

Chat アプリのインタラクション イベントを受信する

このセクションでは、Chat アプリのインタラクション イベントを受信して処理する方法について説明します。

インタラクション イベントを受信するように Chat アプリを構成する

すべての Chat アプリがインタラクティブなわけではありません。たとえば、受信 Webhook は送信メッセージのみ送信でき、ユーザーに応答することはできません。インタラクティブな Chat アプリを作成する場合は、Chat アプリがインタラクション イベントを受信、処理、応答できるエンドポイントを選択する必要があります。Chat アプリの設計の詳細については、Chat アプリの実装アーキテクチャをご覧ください。

インタラクティブな Chat アプリを作成した場合は、Google Chat がインタラクション イベントを送信できるように Google Chat API を構成する必要があります。

  1. Google Cloud コンソールで、Google Chat API のページを開きます。

    Google Chat API ページに移動

  2. [構成] タブをクリックします。
  3. [インタラクティブな機能] セクションで、[インタラクティブ機能を有効にする] をオンに切り替えます。
  4. [機能] で、次のチェックボックスのいずれかまたは両方をオンにします。
    1. 1 対 1 のメッセージの受信: ユーザーがダイレクト メッセージ(DM)スペースで Chat アプリを操作できるようにします。ユーザーが DM スペースでメッセージを送信すると、Chat アプリはインタラクション イベントを受信します。
    2. スペースとグループの会話に参加する: 複数のユーザーがいるスペースに Chat アプリを追加または削除できます。Chat アプリは、スペースで追加または削除されたり、スペースでユーザーが名前リンクを付けたりスラッシュ コマンドを使用したりするたびに、インタラクション イベントを受信します。
  5. [接続設定] で、Google Chat が Chat アプリのインタラクション イベントを送信する場所を指定します。
  6. 省略可: [スラッシュ コマンド] で、1 つ以上のスラッシュ コマンドを追加して構成します。詳細については、スラッシュ コマンドを設定するをご覧ください。
  7. 省略可: [リンク プレビュー] で、Chat アプリでプレビューする URL パターンを 1 つ以上追加して設定します。詳細については、プレビュー リンクをご覧ください。
  8. [保存] をクリックします。

これで、Google Chat からインタラクション イベントを受信するように Chat アプリが構成されました。

Google Chat からのリクエストを認証する

このセクションでは、HTTP エンドポイントで構築されたアプリの場合、エンドポイントへのリクエストが Google Chat から送信されていることを確認する方法について説明します。

Google は、Chat アプリのエンドポイントにインタラクション イベントをディスパッチするために、サービスにリクエストを送信します。Google Chat では、リクエストが Google から送信されていることを確認するために、エンドポイントへのすべての HTTPS リクエストの Authorization ヘッダーに署名なしトークンを含めます。次に例を示します。

POST
Host: yourappurl.com
Authorization: Bearer AbCdEf123456
Content-Type: application/json
User-Agent: Google-Dynamite

上記の例の文字列 AbCdEf123456 は、署名なし認証トークンです。これは、Google が生成する暗号トークンです。署名なしトークンは、オープンソースの Google API クライアント ライブラリを使用して確認できます。

Google Chat リクエストで送信される署名なしトークンの場合、発行元は chat@system.gserviceaccount.com で、audience フィールドは Chat アプリのビルドに使用した Google Cloud プロジェクトの番号に設定されます。たとえば、Chat アプリの Cloud プロジェクト番号が 1234567890 の場合、署名なしトークンの audience フィールドは 1234567890 になります。

Chat アプリのトークンが検証されない場合、サービスは HTTPS レスポンス コード 401 (Unauthorized) でリクエストに応答する必要があります。

Java

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Collections;

import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
import com.google.api.client.googleapis.auth.oauth2.GooglePublicKeysManager;
import com.google.api.client.http.apache.ApacheHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;

/** Tool for verifying JWT Tokens for Apps in Google Chat. */
public class JWTVerify {
  // Bearer Tokens received by apps will always specify this issuer.
  static String CHAT_ISSUER = "chat@system.gserviceaccount.com";

  // Url to obtain the public certificate for the issuer.
  static String PUBLIC_CERT_URL_PREFIX =
      "https://www.googleapis.com/service_accounts/v1/metadata/x509/";

  // Intended audience of the token, which is the project number of the app.
  static String AUDIENCE = "1234567890";

  // Get this value from the request's Authorization HTTPS header.
  // For example, for "Authorization: Bearer AbCdEf123456" use "AbCdEf123456"
  static String BEARER_TOKEN = "AbCdEf123456";

  public static void main(String[] args) throws GeneralSecurityException, IOException {
    JsonFactory factory = new JacksonFactory();

    GooglePublicKeysManager.Builder keyManagerBuilder =
        new GooglePublicKeysManager.Builder(new ApacheHttpTransport(), factory);

    String certUrl = PUBLIC_CERT_URL_PREFIX + CHAT_ISSUER;
    keyManagerBuilder.setPublicCertsEncodedUrl(certUrl);

    GoogleIdTokenVerifier.Builder verifierBuilder =
        new GoogleIdTokenVerifier.Builder(keyManagerBuilder.build());
    verifierBuilder.setIssuer(CHAT_ISSUER);
    GoogleIdTokenVerifier verifier = verifierBuilder.build();

    GoogleIdToken idToken = GoogleIdToken.parse(factory, BEARER_TOKEN);
    if (idToken == null) {
      System.out.println("Token cannot be parsed");
      System.exit(-1);
    }

    // Verify valid token, signed by CHAT_ISSUER.
    if (!verifier.verify(idToken)
        || !idToken.verifyAudience(Collections.singletonList(AUDIENCE))
        || !idToken.verifyIssuer(CHAT_ISSUER)) {
      System.out.println("Invalid token");
      System.exit(-1);
    }

    // Token originates from Google and is targeted to a specific client.
    System.out.println("The token is valid");
  }
}

Python

import sys

from oauth2client import client

# Bearer Tokens received by apps will always specify this issuer.
CHAT_ISSUER = 'chat@system.gserviceaccount.com'

# Url to obtain the public certificate for the issuer.
PUBLIC_CERT_URL_PREFIX = 'https://www.googleapis.com/service_accounts/v1/metadata/x509/'

# Intended audience of the token, which will be the project number of the app.
AUDIENCE = '1234567890'

# Get this value from the request's Authorization HTTPS header.
# For example, for 'Authorization: Bearer AbCdEf123456' use 'AbCdEf123456'.
BEARER_TOKEN = 'AbCdEf123456'

try:
  # Verify valid token, signed by CHAT_ISSUER, intended for a third party.
  token = client.verify_id_token(
      BEARER_TOKEN, AUDIENCE, cert_uri=PUBLIC_CERT_URL_PREFIX + CHAT_ISSUER)

  if token['iss'] != CHAT_ISSUER:
    sys.exit('Invalid issuee')
except:
  sys.exit('Invalid token')

# Token originates from Google and is targeted to a specific client.
print 'The token is valid'

サービスへの HTTP 呼び出しの再試行を処理する

サービスへの HTTPS リクエストが失敗した場合(タイムアウト、一時的なネットワーク障害、2xx 以外の HTTPS ステータス コードなど)、Google Chat は数分以内に配信を数回再試行することがあります(ただし、保証するものではありません)。その結果、特定の状況では Chat アプリが同じメッセージを数回受信する可能性があります。リクエストが正常に完了しても無効なメッセージ ペイロードが返された場合、Google Chat はリクエストを再試行しません。

インタラクション イベントの処理または応答

このセクションでは、Google Chat アプリでインタラクション イベントを処理して応答する方法について説明します。

Chat アプリが Google Chat からインタラクション イベントを受信すると、さまざまな方法で応答できます。多くの場合、インタラクティブな Chat アプリはユーザーにメッセージで応答します。また、Google Chat アプリでは、データソースからの一部の情報の検索や、インタラクション イベント情報の記録など、さまざまなことができます。この処理動作は基本的に、Google Chat アプリの定義です。

Chat アプリは、インタラクション イベントごとにリクエスト本文を受け取ります。これは、イベントを表す JSON ペイロードです。この情報を使用してレスポンスを処理できます。イベント ペイロードの例については、Chat アプリのインタラクション イベントの種類をご覧ください。

次の図は、Google Chat アプリで通常、さまざまな種類のインタラクション イベントを処理または応答する方法を示しています。

Google Chat アプリがインタラクション イベントを処理する方法のアーキテクチャ。

リアルタイムで回答を表示

インタラクション イベントを使用すると、Chat アプリはリアルタイムまたは同期で応答できます。同期レスポンスでは認証は必要ありません。

インタラクション イベントに対する同期レスポンスを作成する方法については、次のガイドをご覧ください。

同期的に応答するには、Chat アプリが 30 秒以内に応答し、その応答をインタラクションが発生したスペースに投稿する必要があります。それ以外の場合、Chat アプリは非同期で応答できます。

非同期で応答する

Chat アプリは、30 秒後にインタラクション イベントに応答したり、インタラクション イベントが生成されたスペースの外部でタスクを実行したりしなければならない場合があります。たとえば、Chat アプリは、長時間実行タスクの完了後にユーザーに応答する必要があります。この場合、Chat アプリは Google Chat API を呼び出すことで、非同期で応答できます。

Chat API を使用してメッセージを作成するには、メッセージを作成するをご覧ください。その他の Chat API メソッドの使用方法については、Chat API の概要をご覧ください。