Ejemplos exhaustivos de la API REST de Discourse

Existen varias guías que cubren diversos usos o explicaciones de la API.

Esta ofrece ejemplos prácticos y completos sobre cómo utilizarla.

:warning: Todos los ejemplos de código en esta guía no pretenden mostrar buenas prácticas ni deben usarse tal cual.
Se omiten o saltan intencionalmente muchas comprobaciones, manejo de errores, etc., para centrarse exclusivamente en el uso de la API.

¿Para qué se utiliza la API?

La mayoría de tus acciones en Discourse (publicar, dar me gusta, editar una configuración, etc.) se realizan mediante la API haciendo peticiones a un endpoint[1].

Por ejemplo, cuando creas un tema en meta, se realiza una solicitud POST a https://meta.discourse.org/posts.json. La solicitud contiene, entre otras cosas, el autor, el título, la categoría, las etiquetas y el contenido de tu publicación.

El uso personalizado de la API suele realizarse para automatizar tareas y a menudo en combinación con otros servicios, como webhooks, scripts, software de terceros y APIs.

Para utilizar la API, es obligatorio tener credenciales de API. Esto se puede hacer en pocos clics siguiendo esta guía: Create and configure an API key

No esperes más y vamos con un primer ejemplo de un caso de uso de la API. :technologist:

Crear un tema mensual

En este ejemplo, utilizaremos curl y cron para crear un tema mensual de “charla libre” en tu foro. Una práctica popular en las comunidades en línea :slight_smile:

Crear la clave de API

Sigue la guía de creación de claves de API. Establece el Nivel de usuario en Usuario único.
El usuario elegido será el autor del tema mensual.
Luego puedes optar por un ámbito Global o un ámbito Granular, en cuyo caso deberá tener al menos el acceso de TópicosEscribir.
Anota tu clave de API generada. :writing_hand:

Crear un comando curl

Desde la línea de comandos de tu servidor, ejecuta este comando para ver si funciona y si se crea correctamente un tema utilizando curl y la API REST de Discourse con tu clave de API:

curl -X POST "https://tu-discourse.com/posts.json" -H "Content-Type: application/json" -H "Api-Key: TU_CLAVE_API" -H "Api-Username: TU_USUARIO" -d "{\"title\": \"Prueba de creación de tema con la API\", \"raw\": \"Y aquí está el contenido del tema\", \"category\": ID_CATEGORIA }"

Reemplaza:

  • tu-discourse.com con el dominio de tu foro
  • TU_CLAVE_API con tu clave de API
  • TU_USUARIO con el nombre de usuario elegido para la clave de API
  • ID_CATEGORIA con el ID de la categoría en la que quieres publicar tu tema.

Si todo está configurado correctamente, se debería crear un nuevo tema de prueba en tu foro, como:

¡La mayor parte del trabajo está hecho en esta etapa! Ahora necesitamos cambiar el título y el contenido del tema por algo más apropiado y configurar la recurrencia de la creación del tema.

Comienza cambiando el título del tema de:
Prueba de creación de tema con la API
a:
Charla libre del mes - $(date +\%B).

Hagamos lo mismo para el contenido, cambiándolo de:
Prueba de creación de tema con la API
a:
¿Qué has apreciado más y menos durante $(date +\%B -d 'mes pasado')?\nSiéntete libre de compartir tus sentimientos y aportar ideas. 🙂

:information_source: Estoy utilizando el comando Unix date para insertar el nombre del mes actual en el título y el nombre del mes anterior en el contenido.

:information_source: \n en el contenido crea una nueva línea.

Puedes usar la línea de comandos y ejecutar la solicitud curl actualizada. Debería haber creado un nuevo tema en tu foro como este:

Configurar el evento recurrente

Crearemos una tarea cron que ejecute el comando curl el primer día de cada mes. :calendar:

Edita el archivo cron con el siguiente comando:

crontab -e

Inserta esta línea al final del archivo (reemplaza el contenido de la solicitud según sea necesario) y guarda la modificación.

0 0 1 * * curl -X POST "https://tu-discourse.com/posts.json" -H "Content-Type: application/json" -H "Api-Key: TU_CLAVE_API" -H "Api-Username: TU_USUARIO" -d "{\"title\": \"Charla libre del mes - $(date +\%B)\", \"raw\": \"¿Qué has apreciado más y menos durante $(date +\%B -d 'mes pasado')?\nSiéntete libre de compartir tus sentimientos y aportar ideas. 🙂\", \"category\": 4 }"

:information_source: La parte 0 0 1 * * define el intervalo en el que se ejecutará el comando. Puedes aprender más sobre la sintaxis aquí: https://crontab.guru

¡Hecho! Tu servidor ahora creará un nuevo tema de “charla libre” el primer día de cada mes, utilizando la API REST de Discourse, una solicitud curl y una tarea cron. :partying_face:

Cambiar automáticamente el esquema de color de un tema

Hagamos que nuestro tema predeterminado utilice un esquema de color que coincida con la estación actual :snowflake: :hibiscus: :sunny: :fallen_leaf:

Utilizaremos Ruby para manejar las comprobaciones de los meses y una tarea cron para ejecutar el script.

Podríamos usar muchas otras formas distintas de Ruby y cron, pero esta guía también pretende mostrar cómo usar la API con diversas herramientas.

Preparar el tema y los esquemas de color

Elige el tema al que quieres cambiar el esquema de color y obtén su ID. Encontrarás el ID en la URL del tema. Por ejemplo, el ID de este tema es 1:

Crea 4 paletas de colores y anota sus IDs también.
Aquí, el ID de la paleta de otoño es 17:

Crear el script

Instala Ruby en tu servidor.

Crea un archivo seasons.rb. Consideraré que está en ~/scripts/ para este ejemplo.

Pon el siguiente contenido en este archivo. Realizaremos una solicitud PUT a nuestro endpoint de temas y enviaremos un payload que contenga el ID del esquema de color:

require 'net/http'
require 'json'
require 'date'

current_month = Date.today.month
color_scheme_id = case current_month
                  when 1..3 then 18 # Invierno
                  when 4..6 then 15 # Primavera
                  when 7..9 then 16 # Verano
                  else           17 # Otoño
                  end

uri = URI('https://tu-discourse.com/admin/themes/ID_TEMA.json')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true

request = Net::HTTP::Put.new(uri, {
  'Api-Key' => 'TU_CLAVE_API',
  'Api-Username' => 'TU_USUARIO',
  'Content-Type' => 'application/json'
})

request.body = JSON.generate({
  "theme" => {
    "color_scheme_id" => color_scheme_id
  }
})

response = http.request(request)

Reemplaza:

  • tu-discourse.com con el dominio de tu foro
  • TU_CLAVE_API con tu clave de API
  • TU_USUARIO con el nombre de usuario elegido para la clave de API
  • ID_TEMA con el ID de tu tema. Puedes encontrarlo al final de la URL de la página de configuración del tema.
    Por ejemplo, en https://tu-discourse.com/admin/customize/themes/38, el ID del tema es 38.

Probemos manualmente tu script.
Primero, configúralo en un esquema de color no estacional en la interfaz de Discourse si aún no lo está.

Luego, ejecuta el script con el siguiente comando:

ruby ~/scripts/seasons.rb

Actualiza tu navegador. El esquema de color utilizado por tu tema debería haber cambiado. :slight_smile:

Lo último que queda por hacer es crear la tarea cron que ejecutará este script el primer día del mes en cada cambio de estación.

Vuelve a ver el primer ejemplo si no recuerdas cómo crear una tarea cron.

0 0 1 1,4,7,10 * ruby ~/scripts/seasons.rb

¡Hecho! Tu foro ahora lucirá nuevos colores al comienzo de cada nueva estación. :sunny: :partying_face:

Recibir una solicitud web en un servidor web y usar sus datos para actualizar un tema de Discourse

¡Este es más complejo! :technologist:

Nuestra herramienta será PHP, lo que significa que asumiremos que tienes un servidor web funcional en algún lugar con PHP instalado.

En este ejemplo, recibiremos una carga útil de webhook de Ko-Fi (un servicio de donaciones) en una página PHP, que luego utilizará los datos recibidos para usar la API de Discourse y actualizar el título y el contenido de un tema.

Más específicamente, actualizará el título del tema con el monto y la fecha de la donación, y añadirá una nueva línea a la tabla que lista las donaciones anteriores (¡incluso hará subir automáticamente el tema :shushing_face:):

Cada vez que un usuario hace una donación, Ko-Fi[2] enviará una solicitud a nuestro script PHP.

Configurar Ko-Fi

Configuré la configuración en la página de webhooks de Ko-Fi simplemente añadiendo la URL de mi archivo PHP y anotando el token de verificación oculto en la sección Avanzado.

En una donación individual, Ko-Fi enviará una carga útil como esta a nuestro script PHP:

data = {
  "verification_token": "d8546b84-c698-4df5-9811-39d35813e2ff",
  "message_id": "a499df4c-7bbb-4061-b4a6-8b9d969da689",
  "timestamp": "2023-10-19T13:35:06Z",
  "type": "Donation",
  "is_public": true,
  "from_name": "Jo Ejemplo",
  "message": "¡Buena suerte con la integración!",
  "amount": "3.00",
  "url": "https://ko-fi.com/Home/CoffeeShop?txid=00000000-1111-2222-3333-444444444444",
  "email": "jo.ejemplo@ejemplo.com",
  "currency": "USD",
  "is_subscription_payment": false,
  "is_first_subscription_payment": false,
  "kofi_transaction_id": "00000000-1111-2222-3333-444444444444",
  "shop_items": null,
  "tier_name": null,
  "shipping": null
}

Recibiremos esta carga útil y luego extraeremos la información que necesitamos:

  • El monto (3.00), que redondearemos a un número entero.

  • El timestamp (2023-10-19T13:35:06Z), que formatearemos en una fecha más legible.

Recibir la carga útil de Ko-Fi

Primero, ponemos el siguiente código en nuestra página PHP para recibir la solicitud de Ko-Fi, donde nos aseguramos de que hemos recibido una solicitud POST y que el valor del token coincide con el proporcionado en la página de webhooks de Ko-Fi. También formateamos el monto y la fecha como se mencionó anteriormente.

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $jsonData = json_decode($_POST['data'], true);

    if ($jsonData['verification_token'] === 'TU_TOKEN_VERIFICACION') {
        $amount = floor(floatval($jsonData['amount']));
        $date = (new DateTime($jsonData['timestamp']))->format('d/m/Y');
    }
}

Reemplaza:

  • TU_TOKEN_VERIFICACION con el token proporcionado por Ko-Fi

Actualizar el título del tema

El siguiente paso es actualizar el título de nuestro tema. Utilizaremos curl en nuestro script PHP para realizar una solicitud PUT al endpoint adecuado.

        $putData = json_encode(['title' => '🥳 Nueva donación: ' . $amount . '€ el ' . $date]);
        $ch = curl_init('https://tu-discourse.com/t/prueba-nuevo-tema/ID_TEMA');
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
        curl_setopt($ch, CURLOPT_POSTFIELDS, $putData);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json',
            'Content-Length: ' . strlen($putData),
            'Api-Key: TU_CLAVE_API',
            'Api-Username: TU_USUARIO'
        ]);
        curl_exec($ch);

Reemplaza:

  • tu-discourse.com con el dominio de tu foro
  • ID_TEMA con el ID correcto del tema
  • TU_CLAVE_API con tu clave de API
  • TU_USUARIO con el nombre de usuario elegido para la clave de API

Actualizar el contenido de la publicación

Para poder agregar nuevo contenido a la primera publicación del tema, primero necesitamos recuperar su contenido actual con una solicitud GET.

        $ch_get = curl_init('https://tu-discourse.com/posts/ID_PUBLICACION.json');
        curl_setopt($ch_get, CURLOPT_RETURNTRANSFER, true);
        $currentContent = json_decode(curl_exec($ch_get), true)['raw'];

Reemplaza:

  • ID_PUBLICACION con el ID correcto de la publicación[3]

Finalmente, necesitamos actualizar el contenido de la publicación agregando una nueva línea a la tabla con el monto y la fecha. Lo haremos con una solicitud PUT.

        $updatedContent = $currentContent . "\n| " . $amount . "€ | " . $date . " |";
        $putPostData = json_encode(['post' => ['raw' => $updatedContent]]);
        $ch_put = curl_init('https://tu-discourse.com/posts/ID_PUBLICACION');
        curl_setopt($ch_put, CURLOPT_CUSTOMREQUEST, 'PUT');
        curl_setopt($ch_put, CURLOPT_POSTFIELDS, $putPostData);
        curl_setopt($ch_put, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json',
            'Content-Length: ' . strlen($putPostData),
            'Api-Key: TU_CLAVE_API',
            'Api-Username: TU_USUARIO'
        ]);
        curl_exec($ch_put);

Reemplaza:

  • tu-discourse.com con el dominio de tu foro
  • ID_PUBLICACION con el ID correcto de la publicación
  • TU_CLAVE_API con tu clave de API
  • TU_USUARIO con el nombre de usuario elegido para la clave de API

El código final se ve así:

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $jsonData = json_decode($_POST['data'], true);

    if ($jsonData['verification_token'] === 'TU_TOKEN_VERIFICACION') {
        $amount = floor(floatval($jsonData['amount']));
        $date = (new DateTime($jsonData['timestamp']))->format('d/m/Y');

        $putData = json_encode(['title' => '🥳 Nueva donación: ' . $amount . '€ el ' . $date]);
        $ch = curl_init('https://tu-discourse.com/t/prueba-nuevo-tema/ID_TEMA');
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
        curl_setopt($ch, CURLOPT_POSTFIELDS, $putData);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json',
            'Content-Length: ' . strlen($putData),
            'Api-Key: TU_CLAVE_API',
            'Api-Username: TU_USUARIO'
        ]);
        curl_exec($ch);

        $ch_get = curl_init('https://tu-discourse.com/posts/ID_PUBLICACION.json');
        curl_setopt($ch_get, CURLOPT_RETURNTRANSFER, true);
        $currentContent = json_decode(curl_exec($ch_get), true)['raw'];

        $updatedContent = $currentContent . "\n| " . $amount . "€ | " . $date . " |";
        $putPostData = json_encode(['post' => ['raw' => $updatedContent]]);
        $ch_put = curl_init('https://tu-discourse.com/posts/ID_PUBLICACION');
        curl_setopt($ch_put, CURLOPT_CUSTOMREQUEST, 'PUT');
        curl_setopt($ch_put, CURLOPT_POSTFIELDS, $putPostData);
        curl_setopt($ch_put, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json',
            'Content-Length: ' . strlen($putPostData),
            'Api-Key: TU_CLAVE_API',
            'Api-Username: TU_USUARIO'
        ]);
        curl_exec($ch_put);

        curl_close($ch);
        curl_close($ch_get);
        curl_close($ch_put);
    } else {
        http_response_code(403);
        echo "Token de verificación inválido.";
    }
} else {
    http_response_code(405);
    echo "Solo se permiten solicitudes POST.";
}
?>

Déjame enfatizar nuevamente la advertencia al principio de esta guía :stuck_out_tongue:

:warning: Todos los ejemplos de código en esta guía no pretenden mostrar buenas prácticas ni deben usarse tal cual.
Se omiten o saltan intencionalmente muchas comprobaciones, manejo de errores, etc., para centrarse exclusivamente en el uso de la API.

Ahora podemos desencadenar una solicitud de prueba desde Ko-Fi y ver cómo actualiza nuestro tema, tanto el título como el contenido. :slight_smile:

¡Eso es todo!
¡Tienes un tema que se actualizará y hará subir cada vez que alguien haga una donación en Ko-Fi! :partying_face:


:information_source: Este tema es un wiki. Siéntete libre de corregir cualquier error que veas y de discutir cómo se podría mejorar esta guía.


  1. Una URL específica, en este contexto. Por ejemplo, https://tu-discourse.com/posts.json ↩︎

  2. Un poco de información sobre su API: https://help.ko-fi.com/hc/en-us/articles/360004162298-Does-Ko-fi-Have-an-API-or-Webhook- ↩︎

  3. El ID de la publicación se puede encontrar en el código HTML. Es un elemento <article> con el siguiente atributo: data-post-id="ID_PUBLICACION" ↩︎

10 Me gusta

Esto es increíble @Canapin y muy necesario, creo. Estuve buscando algo así hace un tiempo. ¡Gracias! :slight_smile:

3 Me gusta

¿Cómo especifico un subtema?
Si tengo jBASE con un subtema de AutoDoc, ¿junto los dos en un tema con algún delimitador (jBASE>AutoDoc) o hay una etiqueta de categoría?

Lo descubrí. Cuando estás en la página de categoría o subcategoría, la URL muestra el # en lugar del nombre de la categoría. Dado que las subcategorías tienen sus propios números, no tienes que mezclar nada.

¿Cómo reemplazo un artículo con información actualizada?

Actualmente, obtengo
{“action”:“create_post”,“errors”:[“El título ya ha sido utilizado”]}
en lugar de una actualización exitosa.

¿No hay una acción diferente para actualizar publicaciones?

Esa es la respuesta. La solicitud curl no especifica una acción.

curl -X POST “http://LOCATION.local/posts.json” -H “Content-Type:
application/json” -H “Api-Key: APIKEY” -H “Api-Username: BOB” -d "{"title": "PL AUTO.DOC.FUN SCS
-TEST Autodoc","raw": " …

¿Qué pasa si usas el endpoint para actualizar un tema?

¿O quizás actualizar una publicación:

No vi eso. Buena observación. Lo intentaré. Gracias.

Actualización: Todavía me falta algo. Parece que la única diferencia es la adición de un edit_reason. Lo intenté y no marcó la diferencia.

Aquí está todo el curl:

curl -X POST “http://localhost.local/posts.json” -H “Content-Type:
application/json” -H “Api-Key: API KEY” -H “Api-Username: BOB” -d “{"title": "Título del Artículo","raw": "El rápido zorro marrón saltó sobre el perro perezoso.26/12/2023.","edit_reason": "auto","category": 66}”

% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1927 0 65 100 1862 1177 33729 --:–:-- --:–:-- --:–:-- 34481

{“action”:“create_post”,“errors”:[“El título ya ha sido utilizado”]}

1 me gusta

¡Para actualizar un tema o una publicación, querrás usar el método PUT en su lugar!

Como señaló Firepup, si deseas actualizar el contenido de una publicación, puedes usar la siguiente API: Discourse API Docs

El problema es que PUT requiere el ID# y no los tengo.
Cuando POSTEO un nuevo tema, recojo el # pero ese número no parece funcionar.
Cuando uso un navegador para ver un tema, muestra un # diferente pero ese número no parece funcionar.

Por ejemplo: Generé un tema y el evento POST devuelve {“id”:3244,…}
La URL para acceder a él dice …test-pl-auto-doc-fun/2803

Entonces, envío este PUT:
curl -X PUT “http://LOCATION.local/posts.json/3244” -H “Content-Type: application/json” -H “Api-Key: KEY” -H “Api-Username: system” -d
“{"title": "Autodoc SCS-TEST PL AUTO.DOC.FUN","raw": "…","edit_reason": "auto","category": 66}”

Y recibo de vuelta el HTML de Página no encontrada.

Debería ser /posts/3244.json.

El id que obtienes de esa solicitud POST es el ID de la publicación (de la primera publicación); es único en todas las publicaciones.

Ambos vídeos de la guía parecen devolver un 404.

1 me gusta

¿Se puede usar la API para llamar al Ayudante de IA?

No lo creo, porque docs.discourse.org no lo menciona. Sin embargo, puedo estar equivocado.

¿Por qué se debe usar un asistente de IA a través de una API :thinking:

para construir un bot conectado a mi sitio web que esté conectado a mi foro con siete años de conocimiento en él para responder preguntas.

o para construir un bot que pueda responder correos electrónicos que esté conectado a mi foro con siete años de conocimiento en él para responder preguntas.

Entonces, probablemente ai-bot sea más lo que estás buscando. ai-helper es el que ayuda al leer y escribir publicaciones.

Como dice la nota, esa no es una lista completa.

Nota: Para cualquier punto final no listado, puedes seguir la guía de ingeniería inversa de la API de Discourse para averiguar cómo usar un punto final de la API.

2 Me gusta

Puedes hacer cualquier cosa desde la UX con la API. Ingeniería inversa de la API de Discourse

Se agregan y cambian cosas en la API todo el tiempo. Me resulta más fácil ver siempre lo que realmente sucede en el navegador.

5 Me gusta

¡excelente idea, gracias!