Exemplos abrangentes da API REST do Discourse

Existem vários guias que cobrem diversos usos ou explicações da API.

Este oferece exemplos práticos e abrangentes sobre como utilizá-la.

:warning: Todos os exemplos de código neste guia não têm a intenção de demonstrar boas práticas ou serem usados exatamente como estão.
Muitas verificações, tratamento de erros e outros elementos são intencionalmente ignorados ou omitidos para focar puramente no uso da API.

Para que a API é usada?

A maioria das suas ações no Discourse (publicar, curtir, editar uma configuração, etc.) é realizada por meio da API, fazendo solicitações a um endpoint[1].

Por exemplo, quando você cria um tópico no meta, uma solicitação POST é enviada para https://meta.discourse.org/posts.json. A solicitação contém, entre outras coisas, o autor, o título, a categoria, as tags e o conteúdo da sua postagem.

Fazer uso personalizado da API geralmente é feito para realizar tarefas automatizadas e frequentemente em conjunto com outros serviços, como webhooks, scripts, softwares de terceiros e APIs.

Para usar a API, é obrigatório possuir credenciais de API. Isso pode ser feito em alguns cliques, seguindo este guia: Create and configure an API key

Não espere mais e vamos para um primeiro exemplo de caso de uso da API. :technologist:

Criando um tópico mensal

Neste exemplo, usaremos curl e cron para criar um tópico mensal de “conversa livre” no seu fórum. Uma prática popular em comunidades online :slight_smile:

Criar a chave da API

Siga o guia de criação de chave da API. Defina o Nível de Usuário como Usuário Único.
O usuário escolhido será o autor do tópico mensal.
Em seguida, você pode optar por um escopo Global ou um escopo Granular. No caso deste último, ele precisará ter pelo menos o acesso Tópicosescrever.
Anote sua Chave de API gerada. :writing_hand:

Criar um comando curl

No terminal do seu servidor, execute este comando para verificar se está funcionando e se um tópico é criado corretamente usando curl e a API REST do Discourse com sua chave de API:

curl -X POST "https://seu-discourse.com/posts.json" -H "Content-Type: application/json" -H "Api-Key: SUA_CHAVE_API" -H "Api-Username: SEU_USUARIO" -d "{\"title\": \"Criação de tópico de teste com a API\", \"raw\": \"E aqui está o conteúdo do tópico\", \"category\": ID_CATEGORIA }"

Substitua:

  • seu-discourse.com pelo domínio do seu fórum
  • SUA_CHAVE_API pela sua chave de API
  • SEU_USUARIO pelo nome de usuário escolhido para a chave de API
  • ID_CATEGORIA pelo ID da categoria onde deseja publicar seu tópico.

Se tudo estiver configurado corretamente, um novo tópico de teste será criado no seu fórum, como:

A maior parte do trabalho já foi feita nesta etapa! Agora precisamos alterar o título e o conteúdo do tópico para algo mais apropriado e configurar a recorrência da criação do tópico.

Comece alterando o título do tópico de:
Criação de tópico de teste com a API
para:
Conversa livre do mês - $(date +\%B).

Faça o mesmo para o conteúdo, alterando de:
Criação de tópico de teste com a API
para:
O que você mais e menos apreciou durante $(date +\%B -d 'last month')?\nSinta-se à vontade para compartilhar seus sentimentos e fornecer ideias. 🙂

:information_source: Estou usando o comando Unix date para inserir o nome do mês atual no título e o nome do mês anterior no conteúdo.

:information_source: \n no conteúdo cria uma nova linha.

Você pode usar o terminal e executar a solicitação curl atualizada. Ela deve ter criado um novo tópico como este no seu fórum:

Configurar o evento recorrente

Vamos criar uma tarefa cron que executará o comando curl no primeiro dia de cada mês. :calendar:

Edite o arquivo cron com o seguinte comando:

crontab -e

Insira esta linha no final do arquivo (substitua o conteúdo da solicitação conforme necessário) e salve a modificação.

0 0 1 * * curl -X POST "https://seu-discourse.com/posts.json" -H "Content-Type: application/json" -H "Api-Key: SUA_CHAVE_API" -H "Api-Username: SEU_USUARIO" -d "{\"title\": \"Conversa livre do mês - $(date +\%B)\", \"raw\": \"O que você mais e menos apreciou durante $(date +\%B -d 'last month')?\nSinta-se à vontade para compartilhar seus sentimentos e fornecer ideias. 🙂\", \"category\": 4 }"

:information_source: A parte 0 0 1 * * define o intervalo em que o comando será executado. Você pode aprender mais sobre a sintaxe aqui: https://crontab.guru

Está feito! Seu servidor agora criará um novo tópico de “conversa livre” no primeiro dia de cada mês, usando a API REST do Discourse, uma solicitação curl e uma tarefa cron. :partying_face:

Alterar automaticamente o esquema de cores de um tema

Vamos fazer com que nosso tema padrão use um esquema de cores que corresponda à estação atual :snowflake: :hibiscus: :sunny: :fallen_leaf:

Usaremos Ruby para verificar os meses e uma tarefa cron para executar o script.

Poderíamos usar muitas outras maneiras além de Ruby e cron, mas este guia também visa mostrar como usar a API com várias ferramentas.

Preparar o tema e os esquemas de cores

Escolha o tema para o qual deseja alterar o esquema de cores e obtenha seu ID. Você encontrará o ID na URL do tema. Por exemplo, o ID deste tema é 1:

Crie 4 paletas de cores e anote também seus IDs.
Aqui, o ID da paleta de Outono é 17:

Criando o script

Instale o Ruby no seu servidor.

Crie um arquivo seasons.rb. Para este exemplo, considerarei que ele está em ~/scripts/.

Coloque o seguinte conteúdo neste arquivo. Faremos uma solicitação PUT para nosso endpoint de tema e enviaremos um payload contendo o ID do esquema de cores:

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

current_month = Date.today.month
color_scheme_id = case current_month
                  when 1..3 then 18 # Inverno
                  when 4..6 then 15 # Primavera
                  when 7..9 then 16 # Verão
                  else           17 # Outono
                  end

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

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

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

response = http.request(request)

Substitua:

  • seu-discourse.com pelo domínio do seu fórum
  • SUA_CHAVE_API pela sua chave de API
  • SEU_USUARIO pelo nome de usuário escolhido para a chave de API
  • THEME_ID pelo ID do seu tema. Você pode encontrá-lo no final da URL da página de configurações do tema.
    Por exemplo, em https://seu-discourse.com/admin/customize/themes/38, o ID do tema é 38.

Vamos testar manualmente seu script.
Primeiro, defina-o para um esquema de cores não sazonal na interface do Discourse, caso ainda não esteja.

Em seguida, execute o script com o seguinte comando:

ruby ~/scripts/seasons.rb

Atualize seu navegador. O esquema de cores usado pelo seu tema deve ter sido alterado. :slight_smile:

A última coisa a fazer é criar o trabalho cron que executará este script no primeiro dia do mês em cada mudança de estação.

Dê uma olhada no primeiro exemplo se não lembrar como criar uma tarefa cron.

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

Está feito! Seu fórum agora terá novas cores no início de cada nova estação! :sunny: :partying_face:

Receber uma solicitação web em um servidor web e usar seus dados para atualizar um tópico do Discourse

Este é mais complexo! :technologist:

Nossa ferramenta será PHP, o que significa que assumiremos que você tem um servidor web funcional em algum lugar com PHP instalado.

Neste exemplo, receberemos um payload de webhook do Ko-Fi (um serviço de doações) em uma página PHP, que então usará os dados recebidos para usar a API do Discourse e atualizar o título e o conteúdo de um tópico.

Mais especificamente, atualizará o título do tópico com o valor e a data da doação e adicionará uma nova linha à tabela que lista as doações anteriores (até mesmo empurrará o tópico automaticamente :shushing_face:):

Sempre que um usuário fizer uma doação, o Ko-Fi[2] enviará uma solicitação para nosso script PHP.

Configurando o Ko-Fi

Configurei a configuração na página de webhooks do Ko-Fi simplesmente adicionando a URL do meu arquivo PHP e anotando o token de verificação oculto na seção Avançado.

Em uma doação única, o Ko-Fi enviará um payload como este para nosso 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 Example",
  "message": "Good luck with the integration!",
  "amount": "3.00",
  "url": "https://ko-fi.com/Home/CoffeeShop?txid=00000000-1111-2222-3333-444444444444",
  "email": "jo.example@example.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
}

Vamos receber este payload e depois extrair as duas informações de que precisamos:

  • O valor (3.00), que arredondaremos para um número inteiro.

  • O timestamp (2023-10-19T13:35:06Z), que formataremos em uma data mais agradável.

Receber o payload do Ko-Fi

Primeiro, colocamos o seguinte código em nossa página PHP para receber a solicitação do Ko-Fi, onde garantimos que recebemos uma solicitação POST e que o valor do token corresponde ao fornecido na página de webhooks do Ko-Fi. Também formatamos o valor e a data como dito anteriormente.

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

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

Substitua:

  • SEU_TOKEN_VERIFICACAO pelo token fornecido pelo Ko-Fi

Atualizar o título do tópico

A próxima etapa é atualizar o título do nosso tópico. Usaremos curl em nosso script PHP para fazer uma solicitação PUT para o endpoint correto.

        $putData = json_encode(['title' => '🥳 Nova doação: ' . $amount . '€ em ' . $date]);
        $ch = curl_init('https://seu-discourse.com/t/test-new-topic/ID_DO_TOPICO');
        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: SUA_CHAVE_API',
            'Api-Username: SEU_USUARIO'
        ]);
        curl_exec($ch);

Substitua:

  • seu-discourse.com pelo domínio do seu fórum
  • ID_DO_TOPICO pelo ID correto do tópico
  • SUA_CHAVE_API pela sua chave de API
  • SEU_USUARIO pelo nome de usuário escolhido para a chave de API

Atualizar o conteúdo da postagem

Para poder adicionar novo conteúdo à primeira postagem do tópico, precisamos primeiro recuperar seu conteúdo atual com uma solicitação GET.

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

Substitua:

  • ID_DA_POSTAGEM pelo ID correto da postagem[3]

Finalmente, precisamos atualizar o conteúdo da postagem adicionando uma nova linha à tabela com o valor e a data. Faremos isso com uma solicitação PUT.

        $updatedContent = $currentContent . "\n| " . $amount . "€ | " . $date . " |";
        $putPostData = json_encode(['post' => ['raw' => $updatedContent]]);
        $ch_put = curl_init('https://seu-discourse.com/posts/ID_DA_POSTAGEM');
        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: SUA_CHAVE_API',
            'Api-Username: SEU_USUARIO'
        ]);
        curl_exec($ch_put);

Substitua:

  • seu-discourse.com pelo domínio do seu fórum
  • ID_DA_POSTAGEM pelo ID correto da postagem
  • SUA_CHAVE_API pela sua chave de API
  • SEU_USUARIO pelo nome de usuário escolhido para a chave de API

O código final fica assim:

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

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

        $putData = json_encode(['title' => '🥳 Nova doação: ' . $amount . '€ em ' . $date]);
        $ch = curl_init('https://seu-discourse.com/t/test-new-topic/ID_DO_TOPICO');
        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: SUA_CHAVE_API',
            'Api-Username: SEU_USUARIO'
        ]);
        curl_exec($ch);

        $ch_get = curl_init('https://seu-discourse.com/posts/ID_DA_POSTAGEM.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://seu-discourse.com/posts/ID_DA_POSTAGEM');
        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: SUA_CHAVE_API',
            'Api-Username: SEU_USUARIO'
        ]);
        curl_exec($ch_put);

        curl_close($ch);
        curl_close($ch_get);
        curl_close($ch_put);
    } else {
        http_response_code(403);
        echo "Token de verificação inválido.";
    }
} else {
    http_response_code(405);
    echo "Apenas solicitações POST são permitidas.";
}
?>

Deixe-me enfatizar novamente o aviso no início deste guia :stuck_out_tongue:

:warning: Todos os exemplos de código neste guia não têm a intenção de demonstrar boas práticas ou serem usados exatamente como estão.
Muitas verificações, tratamento de erros e outros elementos são intencionalmente ignorados ou omitidos para focar puramente no uso da API.

Agora podemos acionar uma solicitação de teste do Ko-Fi e ver como ela atualiza nosso tópico, tanto no título quanto no conteúdo. :slight_smile:

É isso!
Você tem um tópico que será atualizado e empurrado sempre que alguém fizer uma doação no Ko-Fi! :partying_face:


:information_source: Este tópico é um wiki. Sinta-se à vontade para corrigir qualquer erro que encontrar e discutir como este guia pode ser melhorado.


  1. Uma URL específica, neste contexto. Por exemplo, https://seu-discourse.com/posts.json ↩︎

  2. Um pouco de informação sobre a API deles: https://help.ko-fi.com/hc/en-us/articles/360004162298-Does-Ko-fi-Have-an-API-or-Webhook- ↩︎

  3. O ID da postagem pode ser encontrado no código HTML. É um elemento <article> com o seguinte atributo: data-post-id="ID_DA_POSTAGEM" ↩︎

10 curtidas

Isso é incrível @Canapin e muito necessário, eu acho. Eu estava procurando por algo assim há um tempo. Obrigado! :slight_smile:

3 curtidas

Como especifico um subtópico?
Se eu tiver jBASE com um subtópico de AutoDoc, eu junto os dois em um tópico com algum delimitador (jBASE>AutoDoc) ou existe uma tag de categoria?

Eu descobri. Quando você está na página da categoria ou subcategoria, a URL mostra o # em vez do nome da categoria. Como as subcategorias têm seus próprios números, você não precisa misturar nada.

Como substituo um artigo por informações atualizadas?

Atualmente, recebo
{“action”:“create_post”,“errors”:[“Title has already been used”]}
em vez de uma atualização bem-sucedida.

Não existe uma ação diferente para atualizar posts?

Essa é a resposta. O curl solicitante não especifica uma ação.

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": " …

E se você usar o endpoint para atualizar um tópico?

Ou talvez atualizar uma postagem:

Não vi isso. Boa observação. Vou tentar. Obrigado.

Atualização: Ainda está faltando alguma coisa. Parece que a única diferença é a adição de um edit_reason. Tentei isso e não fez diferença.

Aqui está todo o 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": "Title of the Article","raw": "The quick brown fox jumped over the lazy dog.2023-12-26.","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”:[“Title has already been used”]}

1 curtida

Para atualizar um tópico ou postagem, você deve usar o método PUT!

Como Firepup apontou, se você deseja atualizar o conteúdo de uma postagem, pode usar a seguinte API: Discourse API Docs

O problema é que o PUT requer o ID# e eu não os tenho.
Quando eu POST um novo tópico, eu coleto o #, mas esse número não parece funcionar.
Quando eu uso um navegador para ver um tópico, ele mostra um # diferente, mas esse número não parece funcionar.

Por exemplo: Eu gerei um tópico e o evento POST retorna {“id”:3244,…}
A URL para acessá-lo diz …test-pl-auto-doc-fun/2803

Então, eu envio 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}”

E eu recebo de volta o HTML para a Página Não Encontrada.

Deveria ser /posts/3244.json.

O id que você obtém dessa solicitação POST é o ID da postagem (da primeira postagem); ele é exclusivo em todas as postagens.

Ambos os vídeos no guia parecem retornar um 404.

1 curtida

A API pode ser usada para chamar o AI Helper?

Eu não acho, porque docs.discourse.org não menciona isso. Posso estar errado, no entanto.

Por que o assistente de IA deve ser usado via API :thinking:

para construir um bot conectado ao meu site que está conectado ao meu fórum com sete anos de conhecimento nele para responder perguntas.

ou para construir um bot que possa responder a e-mails que está conectado ao meu fórum com sete anos de conhecimento nele para responder perguntas.

Então, provavelmente ai-bot é mais o que você procura. ai-helper é aquele que ajuda ao ler e escrever posts.

Como a nota diz, essa não é uma lista completa.

Nota: Para quaisquer endpoints não listados, você pode seguir o guia engenharia reversa da API do Discourse para descobrir como usar um endpoint de API.

2 curtidas

Qualquer coisa que você possa fazer pela UX você pode fazer com a API. Engenharia reversa da API do Discourse

Coisas são adicionadas e alteradas na API o tempo todo. Eu acho mais fácil sempre ver o que está realmente acontecendo no navegador.

5 curtidas

excelente ideia, obrigado!