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

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

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

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

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

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

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

  1. הלוגיקה של אפליקציית Chat מקבלת מידע משירותים חיצוניים של צד שלישי, כמו מערכת ניהול פרויקטים או כלי ליצירת כרטיסים.
  2. הלוגיקה של אפליקציית Chat מתארחת במערכת בענן או בארגון, שיכולה לשלוח הודעות באמצעות כתובת URL של webhook למרחב משותף ספציפי ב-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. לוחצים על הוספת webhooks.

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

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

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

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

כתיבת הסקריפט של ה-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
    
    # 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 הזה גורמת ל-Chat לחפש שיחה קיימת באמצעות הערך שצוין בשדה threadKey. אם נמצא שרשור כזה, ההודעה תפורסם בתור תשובה לשרשור הזה. אם לא נמצא שרשור, ההודעה תתחיל שרשור חדש שתואם ל-threadKey הזה.

    • משיבים לשרשור או לא עושים כלום. מוסיפים את הפרמטר messageReplyOption=REPLY_MESSAGE_OR_FAIL לכתובת ה-Webhook. העברת פרמטר כתובת ה-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.