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

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

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

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

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

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

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

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

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

Python

  • חשבון Google Workspace במהדורת Business או Enterprise עם גישה ל-Google Chat. בארגון שלכם ב-Google Workspace, המשתמשים צריכים לקבל הרשאה להוסיף webhooks נכנסים ולהשתמש בהם.
  • ‫Python 3.6 ואילך
  • כלי ניהול החבילות pip
  • הספרייה של httplib2. כדי להתקין את הספרייה, מריצים את הפקודה הבאה בממשק שורת הפקודה:

    pip install httplib2
  • מרחב ב-Google Chat. במאמר יצירת מרחב מוסבר איך ליצור מרחב באמצעות Google Chat API. כדי ליצור מרחב ב-Chat, אפשר לעיין במסמכי מרכז העזרה.

Node.js

Java

Apps Script

יצירת webhook

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

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

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

  5. בשדה שם מזינים Quickstart Webhook.

  6. בשדה כתובת ה-URL של האווטאר מזינים את הערך https://developers.google.com/chat/images/chat-product-icon.png.

  7. לוחצים על שמירה.

  8. כדי להעתיק את כתובת ה-URL של ה-webhook, לוחצים על סמל האפשרויות הנוספות ואז על העתקת הקישור.

כתיבת סקריפט ה-webhook

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

בוחרים שפה כדי ללמוד איך ליצור סקריפט של webhook:

Python

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

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

    python/webhook/quickstart.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.
    
    def main():
        """Google Chat incoming webhook quickstart."""
        url = "https://chat.googleapis.com/v1/spaces/SPACE_ID/messages?key=KEY&token=TOKEN"
        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. מחליפים את הערך של המשתנה url בכתובת ה-URL של ה-webhook שהעתקתם כשנרשמתם ל-webhook.

Node.js

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

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

    node/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. מחליפים את הערך של המשתנה url בכתובת ה-URL של ה-webhook שהעתקתם כשנרשמתם ל-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 בכתובת ה-URL של ה-webhook שהעתקתם כשנרשמתם ל-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 בכתובת ה-URL של ה-webhook שהעתקתם כשנרשמתם ל-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);
}

טיפול בשגיאות

בקשות Webhook יכולות להיכשל מסיבות שונות, כולל:

  • בקשה לא חוקית.
  • ה-webhook או המרחב שבו מתארח ה-webhook נמחקים.
  • בעיות לסירוגין כמו קישוריות לרשת או מגבלות מכסה.

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

‫Google Chat API מחזיר שגיאות בתור google.rpc.Status, שכולל שגיאת HTTP‏ code שמציינת את סוג השגיאה שנתקל בה: שגיאת לקוח (סדרה 400) או שגיאת שרת (סדרה 500). כדי לבדוק את כל המיפויים של HTTP, אפשר לעיין במאמר google.rpc.Code.

{
    "code": 503,
    "message": "The service is currently unavailable.",
    "status": "UNAVAILABLE"
}

מידע על קודי סטטוס HTTP וטיפול בשגיאות זמין במאמר בנושא שגיאות.

מגבלות ושיקולים

  • כשיוצרים הודעה באמצעות תגובה לפעולה מאתר אחר (webhook) ב-Google Chat API, התגובה לא מכילה את ההודעה המלאה. התגובה מאכלסת רק את השדות name ו-thread.name.
  • מכסת ה-webhook היא spaces.messages.create לכל מרחב: בקשה אחת בשנייה, שמשותפת לכל ה-webhook במרחב. יכול להיות ש-Chat ידחה גם בקשות webhook שחורגות מ-1 שאילתה בשנייה באותו מרחב. מידע נוסף על מכסות של Chat API זמין במאמר מגבלות שימוש.