יצירת אפליקציית Google Chat כ-webhook

בדף הזה מוסבר איך להגדיר תגובה לפעולה מאתר אחר (webhook) כדי לשלוח הודעות אסינכרוניות למרחב המשותף ב-Chat באמצעות טריגרים חיצוניים. לדוגמה, תוכלו להגדיר אפליקציית מעקב שתיידע את אנשי הצוות התורנים ב-Chat כשהשרת יורד. במאמר שליחת הודעה מוסבר איך שולחים הודעה סינכרונית עם אפליקציית Chat.

כשמשתמשים בארכיטקטורה מהסוג הזה, המשתמשים לא יכולים לתקשר עם התגובה לפעולה מאתר אחר (webhook) או עם האפליקציה החיצונית המחוברת, כי התקשורת היא חד-כיוונית. תגובות לפעולה מאתר אחר (webhook) לא נחשבות לאינטראקציות. הם לא יכולים לענות להודעות של משתמשים או לקבל אירועי אינטראקציה באפליקציות צ'אט. כדי לענות להודעות צריך ליצור אפליקציה ל-Chat במקום webhook.

מבחינה טכנית, תגובה לפעולה מאתר אחר (webhook) היא לא אפליקציה של Chat – כי התגובה לפעולה מאתר אחר מקשרת אפליקציות באמצעות בקשות HTTP רגילות, אבל הדף הזה מתייחס אליה כאפליקציה של Chat, כדי לפשט את הדברים. כל תגובה לפעולה מאתר אחר (webhook) פועלת רק במרחב המשותף ב-Chat שבו היא רשומה. webhooks נכנסים פועלים בצ'אטים אישיים, אבל רק אם אפליקציות צ'אט מופעלות אצל כל המשתמשים. לא ניתן לפרסם webhooks ב-Google Workspace Marketplace.

בתרשים הבא מוצגת הארכיטקטורה של תגובה לפעולה מאתר אחר (webhook) שמחוברת ל-Chat:

ארכיטקטורה של webhooks נכנסים לשליחת הודעות אסינכרוניות ב-Chat.

בתרשים שלמעלה, האפליקציות של Chat כוללות את זרימת המידע הבאה:

  1. הלוגיקה של אפליקציית Chat מקבלת מידע משירותים חיצוניים של צד שלישי, כמו מערכת לניהול פרויקטים או כלי ליצירת כרטיסים.
  2. הלוגיקה של אפליקציית Chat מתארחת בענן או במערכת מקומית שיכולה לשלוח הודעות באמצעות webhook URL למרחב משותף ספציפי ב-Chat.
  3. המשתמשים יכולים לקבל הודעות מאפליקציית Chat במרחב המשותף הספציפי ב-Chat, אבל לא להשתמש באפליקציית Chat.

דרישות מוקדמות

Python

Node.js

Java

Apps Script

יצירת webhook

כדי ליצור תגובה לפעולה מאתר אחר (webhook), צריך לרשום אותה במרחב המשותף ב-Chat שבו רוצים לקבל הודעות, ואז לכתוב סקריפט ששולח הודעות.

רישום ה-webhook הנכנס

  1. פותחים את Chat בדפדפן. אי אפשר להגדיר תגובות לפעולה מאתר אחר (webhook) דרך אפליקציית Chat לנייד.
  2. עוברים למרחב המשותף שבו רוצים להוסיף תגובה לפעולה מאתר אחר (webhook).
  3. ליד השם של המרחב המשותף, לוחצים על החץ להרחבת התצוגה '' ואז על אפליקציות ושילובים.
  4. לוחצים על הוספת webhooks.
  5. בשדה Name (שם), מזינים Quickstart Webhook.
  6. בשדה כתובת URL של הדמות, מזינים https://developers.google.com/chat/images/chat-product-icon.png.
  7. לוחצים על שמירה.
  8. כדי להעתיק את ה-webhook URL, לוחצים על More ואז על Copy link.

כתיבת סקריפט של תגובה לפעולה מאתר אחר (webhook)

סקריפט של תגובה לפעולה מאתר אחר (webhook) לדוגמה שולח הודעה למרחב המשותף שבו ה-webhook רשום. לשם כך, הוא שולח בקשת POST ל-webhook URL. התגובה מ-Chat API כוללת את המופע של Message.

יש לבחור שפה כדי לקבל מידע על יצירת סקריפט של תגובה לפעולה מאתר אחר (webhook):

Python

  1. בספריית העבודה, יוצרים קובץ בשם quickstart.py.

  2. ב-quickstart.py, מדביקים את הקוד הבא:

    python/webhook/quickstart.py
    from json import dumps
    from httplib2 import Http
    
    
    def main():
        """Google Chat incoming webhook quickstart."""
        url = "https://chat.googleapis.com/v1/spaces/SPACE_ID/messages"
        app_message = {"text": "Hello from a Python script!"}
        message_headers = {"Content-Type": "application/json; charset=UTF-8"}
        http_obj = Http()
        response = http_obj.request(
            uri=url,
            method="POST",
            headers=message_headers,
            body=dumps(app_message),
        )
        print(response)
    
    
    if __name__ == "__main__":
        main()
  3. מחליפים את הערך של המשתנה WEBHOOK_URL ב-webhook URL שהעתקתם כשרשמתם את ה-webhook.

Node.js

  1. בספריית העבודה, יוצרים קובץ בשם index.js.

  2. ב-index.js, מדביקים את הקוד הבא:

    צומת/webhook/index.js
    /**
     * Sends asynchronous message to Google Chat
     * @return {Object} response
     */
    async function webhook() {
      const url = "https://chat.googleapis.com/v1/spaces/SPACE_ID/messages"
      const res = await fetch(url, {
        method: "POST",
        headers: {"Content-Type": "application/json; charset=UTF-8"},
        body: JSON.stringify({text: "Hello from a Node script!"})
      });
      return await res.json();
    }
    
    webhook().then(res => console.log(res));
  3. מחליפים את הערך של המשתנה webhookURL ב-webhook URL שהעתקתם כשרשמתם את ה-webhook.

Java

  1. בספריית העבודה, יוצרים קובץ בשם pom.xml.

  2. ב-pom.xml, מעתיקים ומדביקים את הפריטים הבאים:

    java/webhook/pom.xml
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>com.google.chat.webhook</groupId>
      <artifactId>java-webhook-app</artifactId>
      <version>0.1.0</version>
    
      <name>java-webhook-app</name>
      <url>https://github.com/googleworkspace/google-chat-samples/tree/main/java/webhook</url>
    
      <properties>
        <maven.compiler.target>11</maven.compiler.target>
        <maven.compiler.source>11</maven.compiler.source>
      </properties>
    
      <dependencies>
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.9.1</version>
        </dependency>
      </dependencies>
    
      <build>
        <pluginManagement>
          <plugins>
            <plugin>
              <artifactId>maven-compiler-plugin</artifactId>
              <version>3.8.0</version>
            </plugin>
          </plugins>
        </pluginManagement>
      </build>
    </project>
  3. בספריית העבודה, יוצרים את מבנה הספריות הבא: src/main/java.

  4. בספרייה src/main/java, יוצרים קובץ בשם App.java.

  5. ב-App.java, מדביקים את הקוד הבא:

    java/webhook/src/main/java/com/google/chat/webhook/App.java
    import com.google.gson.Gson;
    import java.net.http.HttpClient;
    import java.net.http.HttpRequest;
    import java.net.http.HttpResponse;
    import java.util.Map;
    import java.net.URI;
    
    public class App {
      private static final String URL = "https://chat.googleapis.com/v1/spaces/AAAAGCYeSRY/messages";
      private static final Gson gson = new Gson();
      private static final HttpClient client = HttpClient.newHttpClient();
    
      public static void main(String[] args) throws Exception {
        String message = gson.toJson(Map.of("text", "Hello from Java!"));
    
        HttpRequest request = HttpRequest.newBuilder(
            URI.create(URL))
            .header("accept", "application/json; charset=UTF-8")
            .POST(HttpRequest.BodyPublishers.ofString(message))
            .build();
    
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
    
        System.out.println(response.body());
      }
    }
  6. מחליפים את הערך של המשתנה URL בכתובת ה-webhook URL שהעתקתם כשרשמתם את ה-webhook.

Apps Script

  1. פותחים דפדפן ונכנסים אל Apps Script.

  2. לוחצים על פרויקט חדש.

  3. מדביקים את הקוד הבא:

    apps-script/webhook/webhook.gs
    function webhook() {
      const url = "https://chat.googleapis.com/v1/spaces/SPACE_ID/messages"
      const options = {
        "method": "post",
        "headers": {"Content-Type": "application/json; charset=UTF-8"},
        "payload": JSON.stringify({"text": "Hello from Apps Script!"})
      };
      const response = UrlFetchApp.fetch(url, options);
      console.log(response);
    }
  4. מחליפים את הערך של המשתנה url בכתובת ה-webhook URL שהעתקתם כשרשמתם את ה-webhook.

הפעלת הסקריפט של תגובה לפעולה מאתר אחר (webhook)

ב-CLI, מריצים את הסקריפט:

Python

  python3 quickstart.py

Node.js

  node index.js

Java

  mvn compile exec:java -Dexec.mainClass=App

Apps Script

  • לוחצים על Run.

כשמריצים את הקוד, התגובה לפעולה מאתר אחר (webhook) שולחת הודעה למרחב המשותף שבו היא רשמת.

התחלה של שרשור הודעות או מענה להן

  1. צריך לציין את הקוד spaces.messages.thread.threadKey כחלק מגוף הבקשה לצ'אט. הערכים הבאים יכולים לשמש בתור התחלה של שרשור, בהתאם לתשובה של threadKey:

    • כשאתם מתחילים שרשור, צריך להגדיר את threadKey כמחרוזת שרירותית, אבל לרשום את הערך הזה כדי לפרסם תשובה לשרשור.

    • כשעונים לשרשור, צריך לציין את threadKey שהוגדר כשהשרשור הופעל. לדוגמה, כדי לפרסם תשובה בשרשור שבו ההודעה הראשונה השתמשה ב-MY-THREAD, צריך להגדיר את MY-THREAD.

  2. הגדרת התנהגות השרשור אם ה-threadKey שצוין לא נמצא:

    • לענות לשרשור או להתחיל שרשור חדש. מוסיפים את הפרמטר messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD ל-webhook URL. העברת הפרמטר הזה של כתובת ה-URL גורמת ל-Chat לחפש שרשור קיים באמצעות threadKey שצוין. אם תימצא תשובה, ההודעה תפורסם כתשובה לשרשור הזה. אם לא נמצאו הודעות, ההודעה תתחיל שרשור חדש שקשור לאותו threadKey.

    • לענות לשרשור או לא לעשות כלום. מוסיפים את הפרמטר messageReplyOption=REPLY_MESSAGE_OR_FAIL ל-webhook URL. העברת הפרמטר הזה של כתובת ה-URL גורמת ל-Chat לחפש שרשור קיים באמצעות threadKey שצוין. אם תימצא תשובה, ההודעה תפורסם כתשובה לשרשור הזה. אם לא נמצאו הודעות, ההודעה לא תישלח.

    מידע נוסף זמין כאן: messageReplyOption.

דוגמת הקוד הבאה מתחילה בשרשור הודעות או עונה לו:

Python

python/webhook/thread-reply.py
from json import dumps
from httplib2 import Http

# Copy the webhook URL from the Chat space where the webhook is registered.
# The values for SPACE_ID, KEY, and TOKEN are set by Chat, and are included
# when you copy the webhook URL.
#
# Then, append messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD to the
# webhook URL.


def main():
    """Google Chat incoming webhook that starts or replies to a message thread."""
    url = "https://chat.googleapis.com/v1/spaces/SPACE_ID/messages?key=KEY&token=TOKEN&messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD"
    app_message = {
        "text": "Hello from a Python script!",
        # To start a thread, set threadKey to an arbitratry string.
        # To reply to a thread, specify that thread's threadKey value.
        "thread": {"threadKey": "THREAD_KEY_VALUE"},
    }
    message_headers = {"Content-Type": "application/json; charset=UTF-8"}
    http_obj = Http()
    response = http_obj.request(
        uri=url,
        method="POST",
        headers=message_headers,
        body=dumps(app_message),
    )
    print(response)


if __name__ == "__main__":
    main()

Node.js

node/webhook/thread-reply.js
/**
 * Sends asynchronous message to Google Chat
 * @return {Object} response
 */
async function webhook() {
  const url = "https://chat.googleapis.com/v1/spaces/SPACE_ID/messages?key=KEY&token=TOKEN&messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD"
  const res = await fetch(url, {
    method: "POST",
    headers: {"Content-Type": "application/json; charset=UTF-8"},
    body: JSON.stringify({
      text: "Hello from a Node script!",
      thread: {threadKey: "THREAD_KEY_VALUE"}
    })
  });
  return await res.json();
}

webhook().then(res => console.log(res));

Apps Script

apps-script/webhook/thread-reply.gs
function webhook() {
  const url = "https://chat.googleapis.com/v1/spaces/SPACE_ID/messages?key=KEY&token=TOKEN&messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD"
  const options = {
    "method": "post",
    "headers": {"Content-Type": "application/json; charset=UTF-8"},
    "payload": JSON.stringify({
      "text": "Hello from Apps Script!",
      "thread": {"threadKey": "THREAD_KEY_VALUE"}
    })
  };
  const response = UrlFetchApp.fetch(url, options);
  console.log(response);
}