สร้างแอป Google Chat เป็นเว็บฮุค

หน้านี้อธิบายวิธีตั้งค่าเว็บฮุคเพื่อส่งข้อความแบบไม่พร้อมกันไปยังพื้นที่ทำงานใน Chat โดยใช้ทริกเกอร์ภายนอก ตัวอย่างเช่น คุณสามารถกำหนดค่าแอปพลิเคชันการตรวจสอบเพื่อแจ้งให้บุคลากรที่ปฏิบัติหน้าที่ทราบใน Chat เมื่อเซิร์ฟเวอร์ล่ม หากต้องการส่งข้อความแบบพร้อมกัน ด้วยแอป Chat โปรดดูหัวข้อ ส่งข้อความ

การออกแบบสถาปัตยกรรมประเภทนี้จะทำให้ผู้ใช้โต้ตอบกับเว็บฮุคหรือแอปพลิเคชันภายนอกที่เชื่อมต่อไม่ได้เนื่องจากการสื่อสารเป็นแบบทางเดียว เว็บฮุคไม่ใช่การสนทนา จึงไม่สามารถตอบกลับหรือรับข้อความจากผู้ใช้หรือ เหตุการณ์การโต้ตอบของแอป Chat ได้ หากต้องการตอบกลับข้อความ ให้สร้างแอป Chat แทนเว็บฮุค

แม้ว่าเว็บฮุคจะไม่ใช่แอป Chat ในทางเทคนิค (เว็บฮุคเชื่อมต่อแอปพลิเคชันโดยใช้คำขอ HTTP มาตรฐาน) แต่หน้านี้จะเรียกว่าแอป Chat เพื่อให้เข้าใจง่าย เว็บฮุคแต่ละรายการจะทำงานในพื้นที่ทำงานใน Chat ที่ลงทะเบียนไว้เท่านั้น เว็บฮุคขาเข้าจะทำงานในข้อความส่วนตัว แต่จะทำงานได้ก็ต่อเมื่อ ผู้ใช้ทุกคนเปิดใช้ แอป Chat คุณไม่สามารถเผยแพร่เว็บฮุคไปยัง Google Workspace Marketplace ได้

แผนภาพต่อไปนี้แสดงสถาปัตยกรรมของเว็บฮุคที่เชื่อมต่อกับ Chat

สถาปัตยกรรมสำหรับเว็บฮุคขาเข้าเพื่อส่งข้อความแบบไม่พร้อมกันไปยัง Chat

ในแผนภาพก่อนหน้า แอป Chat มีโฟลว์ข้อมูลดังนี้

  1. ตรรกะของแอป Chat จะรับข้อมูลจากบริการของบุคคลที่สามภายนอก เช่น ระบบการจัดการโปรเจ็กต์หรือเครื่องมือออกตั๋ว
  2. ตรรกะของแอป Chat จะโฮสต์อยู่ในระบบคลาวด์หรือระบบภายในองค์กรที่สามารถส่งข้อความได้โดยใช้ URL ของเว็บฮุคไปยังพื้นที่ทำงานใน Chat ที่เฉพาะเจาะจง
  3. ผู้ใช้สามารถรับข้อความจากแอป Chat ในพื้นที่ทำงานใน Chat ที่เฉพาะเจาะจงนั้นได้ แต่จะโต้ตอบกับแอป Chat ไม่ได้

ข้อกำหนดเบื้องต้น

Node.js

Python

Java

Apps Script

สร้างเว็บฮุค

หากต้องการสร้างเว็บฮุค ให้ลงทะเบียนเว็บฮุคในพื้นที่ทำงานใน Chat ที่คุณต้องการรับข้อความ แล้วเขียนสคริปต์ที่ส่งข้อความ

ลงทะเบียนเว็บฮุคขาเข้า

  1. เปิด Chat ในเบราว์เซอร์ คุณกำหนดค่าเว็บฮุคจากแอป Chat บนอุปกรณ์เคลื่อนที่ไม่ได้
  2. ไปที่พื้นที่ทำงานที่ต้องการเพิ่มเว็บฮุค
  3. คลิกลูกศรขยายเพิ่มเติม ข้างชื่อพื้นที่ทำงาน แล้วคลิกแอปและการผสานรวม
  4. คลิก เพิ่มเว็บฮุค

  5. ในช่องชื่อ ให้ป้อน Quickstart Webhook

  6. ในช่องURL รูปโปรไฟล์ ให้ป้อน https://developers.google.com/chat/images/chat-product-icon.png

  7. คลิกบันทึก

  8. หากต้องการคัดลอก URL ของเว็บฮุค ให้คลิก เพิ่มเติม แล้วคลิก คัดลอกลิงก์

    URL ของเว็บฮุคมีพารามิเตอร์ 2 รายการ ได้แก่ key ซึ่งเป็นค่าทั่วไปที่ใช้ร่วมกัน ระหว่างเว็บฮุค และ token ซึ่งเป็นค่าที่ไม่ซ้ำกันที่คุณต้องเก็บไว้ เป็นความลับเพื่อรักษาความปลอดภัยของเว็บฮุค

เขียนสคริปต์เว็บฮุค

สคริปต์เว็บฮุคตัวอย่างจะส่งข้อความไปยังพื้นที่ทำงานที่ลงทะเบียนเว็บฮุคไว้โดยส่งคำขอ POST ไปยัง URL ของเว็บฮุค Chat API จะตอบกลับด้วยอินสแตนซ์ของ Message

เลือกภาษาเพื่อดูวิธีสร้างสคริปต์เว็บฮุค

Node.js

  1. สร้างไฟล์ชื่อ index.js ในไดเรกทอรีที่ทำงานอยู่

  2. วางโค้ดต่อไปนี้ใน index.js

    solutions/webhook-chat-app/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?key=KEY&token=TOKEN"
      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 ของเว็บฮุคที่คุณคัดลอกไว้เมื่อลงทะเบียนเว็บฮุค

Python

  1. สร้างไฟล์ชื่อ quickstart.py ในไดเรกทอรีที่ทำงานอยู่

  2. วางโค้ดต่อไปนี้ใน quickstart.py

    solutions/webhook-chat-app/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 ของเว็บฮุคที่คุณคัดลอกไว้เมื่อลงทะเบียนเว็บฮุค

Java

  1. สร้างไฟล์ชื่อ pom.xml ในไดเรกทอรีที่ทำงานอยู่

  2. คัดลอกและวางโค้ดต่อไปนี้ใน pom.xml

    solutions/webhook-chat-app/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>webhook-app</artifactId>
      <version>0.1.0</version>
      <name>webhook-app</name>
    
      <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. สร้างไฟล์ชื่อ App.java ในไดเรกทอรี src/main/java

  5. วางโค้ดต่อไปนี้ใน App.java

    solutions/webhook-chat-app/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/SPACE_ID/messages?key=KEY&token=TOKEN";
      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 ของเว็บฮุคที่คุณคัดลอกไว้เมื่อลงทะเบียนเว็บฮุค

Apps Script

  1. ไปที่ Apps Script ในเบราว์เซอร์

  2. คลิกโปรเจ็กต์ใหม่

  3. วางโค้ดต่อไปนี้

    solutions/webhook-chat-app/webhook.gs
    function webhook() {
      const url = "https://chat.googleapis.com/v1/spaces/SPACE_ID/messages?key=KEY&token=TOKEN"
      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 ของเว็บฮุคที่คุณคัดลอกไว้เมื่อลงทะเบียนเว็บฮุค

เรียกใช้สคริปต์เว็บฮุค

เรียกใช้สคริปต์ใน CLI โดยใช้คำสั่งต่อไปนี้

Node.js

  node index.js

Python

  python3 quickstart.py

Java

  mvn compile exec:java -Dexec.mainClass=App

Apps Script

  • คลิกเรียกใช้

เมื่อเรียกใช้โค้ด เว็บฮุคจะส่งข้อความไปยังพื้นที่ทำงานที่คุณลงทะเบียนไว้

เริ่มหรือตอบกลับชุดข้อความ

  1. ระบุ spaces.messages.thread.threadKey เป็นส่วนหนึ่งของเนื้อหาคำขอข้อความ ใช้ค่าต่อไปนี้สำหรับ threadKey โดยขึ้นอยู่กับว่าคุณจะเริ่มหรือตอบกลับชุดข้อความ

    • หากจะเริ่มชุดข้อความ ให้ตั้งค่า threadKey เป็นสตริงที่กำหนดเอง แต่จดค่านี้ไว้เพื่อโพสต์คำตอบในชุดข้อความ

    • หากจะตอบกลับชุดข้อความ ให้ระบุ threadKey ที่ตั้งไว้เมื่อเริ่มชุดข้อความ เช่น หากต้องการโพสต์คำตอบในชุดข้อความที่ข้อความเริ่มต้นใช้ MY-THREAD ให้ตั้งค่า MY-THREAD

  2. กำหนดลักษณะการทำงานของชุดข้อความหากไม่พบ threadKey ที่ระบุ

    • ตอบกลับชุดข้อความหรือเริ่มชุดข้อความใหม่ เพิ่มพารามิเตอร์ messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD ลงใน URL ของเว็บฮุค การส่งพารามิเตอร์ URL นี้จะทำให้ Chat ค้นหาชุดข้อความที่มีอยู่โดยใช้ threadKey ที่ระบุ หากพบชุดข้อความ ระบบจะโพสต์ข้อความเป็นการตอบกลับชุดข้อความนั้น หากไม่พบชุดข้อความ ระบบจะเริ่มชุดข้อความใหม่ที่สอดคล้องกับ threadKey นั้น

    • ตอบกลับชุดข้อความหรือไม่ทำอะไรเลย เพิ่มพารามิเตอร์ messageReplyOption=REPLY_MESSAGE_OR_FAIL ลงใน URL ของเว็บฮุค การส่งพารามิเตอร์ URL นี้จะทำให้ Chat ค้นหาชุดข้อความที่มีอยู่โดยใช้ threadKey ที่ระบุ หากพบชุดข้อความ ระบบจะโพสต์ข้อความเป็นการตอบกลับชุดข้อความนั้น หากไม่พบชุดข้อความ ระบบจะไม่ส่งข้อความ

    ดูข้อมูลเพิ่มเติมได้ที่ messageReplyOption

ตัวอย่างโค้ดต่อไปนี้จะเริ่มหรือตอบกลับชุดข้อความ

Node.js

solutions/webhook-chat-app/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));

Python

solutions/webhook-chat-app/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()

Java

solutions/webhook-chat-app/src/main/java/com/google/chat/webhook/AppThread.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/SPACE_ID/messages?key=KEY&token=TOKEN&messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD";
  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!",
      "thread", Map.of(
        "threadKey", "THREAD_KEY_VALUE"
      )
    ));

    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());
  }
}

Apps Script

solutions/webhook-chat-app/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);
}

จัดการข้อผิดพลาด

คำขอเว็บฮุคล้มเหลวได้ด้วยเหตุผลหลายประการ ซึ่งรวมถึง

  • คำขอไม่ถูกต้อง
  • เว็บฮุคหรือพื้นที่ทำงานที่โฮสต์เว็บฮุคถูกลบ
  • ปัญหาที่เกิดขึ้นเป็นระยะๆ เช่น การเชื่อมต่อเครือข่ายหรือขีดจำกัดโควต้า

เมื่อสร้างเว็บฮุค คุณควรจัดการข้อผิดพลาดอย่างเหมาะสมโดยทำดังนี้

  • บันทึกการล้มเหลว
  • สำหรับข้อผิดพลาดที่อิงตามเวลา โควต้า หรือการเชื่อมต่อเครือข่าย ให้ลองส่งคำขออีกครั้งโดยใช้ Exponential Backoff
  • ไม่ทำอะไรเลย ซึ่งเหมาะในกรณีที่การส่งข้อความเว็บฮุคไม่สำคัญ

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 และจัดการข้อผิดพลาดได้ที่ ข้อผิดพลาด

ข้อจำกัดและข้อควรพิจารณา

  • เมื่อ สร้างข้อความ ด้วยเว็บฮุคใน Google Chat API การตอบกลับจะไม่มีข้อความทั้งหมด การตอบกลับจะป้อนข้อมูลเฉพาะช่อง name และ thread.name
  • เว็บฮุคอยู่ภายใต้โควต้าต่อพื้นที่ทำงานสำหรับ spaces.messages.create ซึ่งคือ 1 คำขอต่อวินาที โดยใช้ร่วมกันระหว่างเว็บฮุคทั้งหมดในพื้นที่ทำงาน นอกจากนี้ Chat อาจปฏิเสธคำขอเว็บฮุคที่เกิน 1 คำขอต่อวินาทีในพื้นที่ทำงานเดียวกัน ดูข้อมูลเพิ่มเติมเกี่ยวกับโควต้า Chat API ได้ที่ ขีดจำกัดการใช้งาน