Compila una app de Google Chat como webhook

En esta página, se describe cómo configurar un webhook para enviar mensajes asíncronos a un espacio de Chat con activadores externos. Por ejemplo, puedes configurar una aplicación de supervisión para que notifique al personal de guardia en Chat cuando un servidor deje de funcionar. Para enviar un mensaje síncrono con una app de Chat, consulta Envía un mensaje.

Con este tipo de diseño de arquitectura, los usuarios no pueden interactuar con el webhook ni con la aplicación externa conectada porque la comunicación es unidireccional. Los webhooks no son conversacionales. No pueden responder a los mensajes de los usuarios ni recibirlos, ni tampoco pueden recibir eventos de interacción de la app de Chat. Para responder mensajes, crea una app de Chat en lugar de un webhook.

Si bien técnicamente un webhook no es una app de Chat (los webhooks conectan aplicaciones con solicitudes HTTP estándar), en esta página se hace referencia a él como una app de Chat para simplificar la explicación. Cada webhook solo funciona en el espacio de Chat en el que está registrado. Los webhooks entrantes funcionan en los mensajes directos, pero solo cuando todos los usuarios tienen habilitadas las apps de Chat. No puedes publicar webhooks en Google Workspace Marketplace.

En el siguiente diagrama, se muestra la arquitectura de un webhook conectado a Chat:

Arquitectura de los webhooks entrantes para enviar mensajes asíncronos a Chat.

En el diagrama anterior, una app de Chat tiene el siguiente flujo de información:

  1. La lógica de la app de Chat recibe información de servicios externos de terceros, como un sistema de administración de proyectos o una herramienta de tickets.
  2. La lógica de la app de Chat se aloja en un sistema local o en la nube que puede enviar mensajes a un espacio de Chat específico a través de una URL de webhook.
  3. Los usuarios pueden recibir mensajes de la app de Chat en ese espacio de Chat específico, pero no pueden interactuar con la app de Chat.

Requisitos previos

Python

  • Una cuenta de Google Workspace para empresas o Enterprise con acceso a Google Chat Tu organización de Google Workspace debe permitir que los usuarios agreguen y usen webhooks entrantes.
  • Python 3.6 o una versión posterior
  • La herramienta de administración de paquetes pip
  • Biblioteca httplib2 Para instalar la biblioteca, ejecuta el siguiente comando en tu interfaz de línea de comandos:

    pip install httplib2
  • Un espacio de Google Chat. Para crear uno con la API de Google Chat, consulta Crea un espacio. Para crear uno en Chat, visita la documentación del Centro de ayuda.

Node.js

Java

Apps Script

Crea un webhook

Para crear un webhook, regístralo en el espacio de Chat en el que deseas recibir mensajes y, luego, escribe un script que envíe mensajes.

Registra el webhook entrante

  1. En un navegador, abre Chat. Los webhooks no se pueden configurar desde la app de Chat para dispositivos móviles.
  2. Ve al espacio en el que quieras agregar un webhook.
  3. Junto al título del espacio, haz clic en la flecha de expandir más y, luego, en Apps & integrations.
  4. Haz clic en Agregar webhooks.

  5. En el campo Nombre, ingresa Quickstart Webhook.

  6. En el campo URL del avatar, ingresa https://developers.google.com/chat/images/chat-product-icon.png.

  7. Haz clic en Guardar.

  8. Para copiar la URL del webhook, haz clic en Más y, luego, en Copiar vínculo.

Escribe la secuencia de comandos del webhook

La secuencia de comandos de webhook de ejemplo envía un mensaje al espacio en el que se registró el webhook enviando una solicitud POST a la URL del webhook. La API de Chat responde con una instancia de Message.

Selecciona un idioma para aprender a crear una secuencia de comandos de webhook:

Python

  1. En tu directorio de trabajo, crea un archivo llamado quickstart.py.

  2. En quickstart.py, pega el siguiente código:

    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. Reemplaza el valor de la variable url por la URL del webhook que copiaste cuando lo registraste.

Node.js

  1. En tu directorio de trabajo, crea un archivo llamado index.js.

  2. En index.js, pega el siguiente código:

    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. Reemplaza el valor de la variable url por la URL del webhook que copiaste cuando lo registraste.

Java

  1. En tu directorio de trabajo, crea un archivo llamado pom.xml.

  2. En pom.xml, copia y pega lo siguiente:

    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. En tu directorio de trabajo, crea la siguiente estructura de directorios src/main/java.

  4. En el directorio src/main/java, crea un archivo llamado App.java.

  5. En App.java, pega el siguiente código:

    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. Reemplaza el valor de la variable URL por la URL del webhook que copiaste cuando lo registraste.

Apps Script

  1. En un navegador, ve a Apps Script.

  2. Haz clic en Nuevo proyecto.

  3. Pega el siguiente código:

    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. Reemplaza el valor de la variable url por la URL del webhook que copiaste cuando lo registraste.

Ejecuta la secuencia de comandos del webhook

En una CLI, ejecuta la secuencia de comandos:

Python

  python3 quickstart.py

Node.js

  node index.js

Java

  mvn compile exec:java -Dexec.mainClass=App

Apps Script

  • Haz clic en Ejecutar.

Cuando ejecutas el código, el webhook envía un mensaje al espacio en el que lo registraste.

Cómo iniciar o responder una conversación

  1. Especifica spaces.messages.thread.threadKey como parte del cuerpo de la solicitud del mensaje. Según si inicias un hilo o respondes a uno, usa los siguientes valores para threadKey:

    • Si inicias un hilo, establece threadKey en una cadena arbitraria, pero anota este valor para publicar una respuesta en el hilo.

    • Si respondes a una conversación, especifica el threadKey que se configuró cuando se inició la conversación. Por ejemplo, para publicar una respuesta en el hilo en el que el mensaje inicial usó MY-THREAD, configura MY-THREAD.

  2. Define el comportamiento del subproceso si no se encuentra el threadKey especificado:

    • Responder una conversación o iniciar una nueva Agrega el parámetro messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD a la URL del webhook. Si se pasa este parámetro de URL, Chat buscará un subproceso existente con el threadKey especificado. Si se encuentra una, el mensaje se publica como respuesta a esa conversación. Si no se encuentra ninguno, el mensaje inicia un nuevo hilo correspondiente a ese threadKey.

    • Responder una conversación o no hacer nada Agrega el parámetro messageReplyOption=REPLY_MESSAGE_OR_FAIL a la URL del webhook. Si se pasa este parámetro de URL, Chat buscará un subproceso existente con el threadKey especificado. Si se encuentra una, el mensaje se publica como respuesta a esa conversación. Si no se encuentra ninguno, no se envía el mensaje.

    Para obtener más información, consulta messageReplyOption.

En el siguiente código de ejemplo, se inicia un hilo de mensajes o se responde a uno:

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

Soluciona errores

Las solicitudes de webhook pueden fallar por varios motivos, incluidos los siguientes:

  • Solicitud no válida.
  • Se borró el webhook o el espacio que lo aloja.
  • Problemas intermitentes, como conectividad de red o límites de cuota

Cuando compiles tu webhook, debes controlar los errores de forma adecuada de la siguiente manera:

La API de Google Chat devuelve errores como un google.rpc.Status, que incluye un error HTTP code que indica el tipo de error que se produjo: un error del cliente (serie 400) o un error del servidor (serie 500). Para revisar todas las asignaciones de HTTP, consulta google.rpc.Code.

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

Para obtener información sobre cómo interpretar los códigos de estado HTTP y controlar los errores, consulta Errores.

Limitaciones y consideraciones

  • Cuando crea un mensaje con un webhook en la API de Google Chat, la respuesta no contiene el mensaje completo. La respuesta solo propaga los campos name y thread.name.
  • Los webhooks están sujetos a la cuota por espacio para spaces.messages.create: 1 solicitud por segundo, compartida entre todos los webhooks del espacio. Es posible que Chat también rechace las solicitudes de webhook que superen 1 consulta por segundo en el mismo espacio. Para obtener más información sobre las cuotas de la API de Chat, consulta Límites de uso.