Discourse REST API 全面示例

这里有 几份指南,涵盖了各种 API 用途或说明。

本文档提供实用且全面的示例,介绍如何使用 API。

:warning: 本指南中的所有代码示例并非旨在展示最佳实践,也不建议直接照搬使用。
为了专注于 API 的使用,我们有意忽略或省略了许多检查、错误处理等内容。

API 的用途是什么?

你在 Discourse 中的大多数操作(发帖、点赞、编辑设置等)都是通过向某个端点[1] 发送请求,利用 API 来完成的。

例如,当你在 meta 上创建一个主题时,会向 https://meta.discourse.org/posts.json 发送一个 POST 请求。该请求中包含作者、标题、分类、标签以及帖子内容等信息。

自定义使用 API 通常是为了实现自动化任务,并且经常与其他服务配合使用,例如 Webhooks、脚本、第三方软件和 API。

要使用 API,必须拥有 API 凭证。只需几次点击即可创建,具体步骤请遵循本指南:Create and configure an API key

别再等待,让我们来看一个 API 使用场景的实际示例吧。:technologist:

创建月度主题

在本示例中,我们将使用 curlcron 在你的论坛上创建一个每月的“自由讨论”主题。这是在线社区中非常流行的做法 :slight_smile:

创建 API 密钥

按照 API 密钥创建指南 进行操作。将 用户级别 设置为“单个用户”。
所选用户将成为月度主题的作者。
然后你可以选择 全局 范围或 细粒度 范围;如果选择后者,则至少需要 主题写入 权限。
记下你生成的 API 密钥。:writing_hand:

创建 curl 命令

从服务器的命令行运行以下命令,以测试其是否正常工作,并确认使用 curl 和 Discourse REST API 以及你的 API 密钥能否正确创建主题:

curl -X POST "https://your-discourse.com/posts.json" -H "Content-Type: application/json" -H "Api-Key: YOUR_API_KEY" -H "Api-Username: YOUR_USERNAME" -d "{\"title\": \"使用 API 创建测试主题\", \"raw\": \"这里是帖子的内容\", \"category\": CATEGORY_ID }"

替换以下内容:

  • your-discourse.com 为你的论坛域名
  • YOUR_API_KEY 为你的 API 密钥
  • YOUR_USERNAME 为 API 密钥所选的用户名
  • CATEGORY_ID 为你希望发布主题的分类 ID

如果一切配置正确,你的论坛上应该会创建一个新的测试主题,如下所示:

大部分工作已经完成!现在我们需要将主题标题和内容更改为更合适的内容,并设置主题创建的周期性。

首先将主题标题从:
使用 API 创建测试主题
更改为:
本月自由讨论 - $(date +\%B)

同样,将内容从:
使用 API 创建测试主题
更改为:
你在 $(date +\%B -d 'last month') 期间最喜欢和最不喜欢的是什么?\n欢迎分享你的感受并提供建议。🙂

:information_source: 我使用了 date Unix 命令,在标题中插入当前月份名称,在内容中插入上个月的名称。

:information_source: 内容中的 \n 会创建一个新行。

你可以使用命令行运行更新后的 curl 请求。它应该会在你的论坛上创建一个类似这样的新主题:

设置周期性事件

我们将创建一个 cron 任务,在每月的第一天运行 curl 命令。:calendar:

使用以下命令编辑 cron 文件:

crontab -e

在文件末尾插入以下行(根据需要替换请求内容),然后保存修改。

0 0 1 * * curl -X POST "https://your-discourse.com/posts.json" -H "Content-Type: application/json" -H "Api-Key: YOUR_API_KEY" -H "Api-Username: YOUR_USERNAME" -d "{\"title\": \"本月自由讨论 - $(date +\%B)\", \"raw\": \"你在 $(date +\%B -d 'last month') 期间最喜欢和最不喜欢的是什么?\n欢迎分享你的感受并提供建议。🙂\", \"category\": 4 }"

:information_source: 0 0 1 * * 部分定义了命令运行的时间间隔。你可以在这里了解更多语法:https://crontab.guru

完成!现在你的服务器将使用 Discourse REST API、curl 请求和 cron 任务,在每月的第一天自动创建一个“自由讨论”主题。:partying_face:

自动更改主题的颜色方案

让我们让我们的默认主题根据当前季节使用相应的颜色方案 :snowflake: :hibiscus: :sunny: :fallen_leaf:

我们将使用 Ruby 来处理月份检查,并使用 cron 任务来执行脚本。

除了 Ruby 和 cron,我们还有很多其他方法,但本指南也旨在展示如何使用 API 与各种工具配合。

准备主题和颜色方案

选择你要更改颜色方案的主题,并获取其 ID。你可以在主题的 URL 中找到该 ID。例如,这个主题的 ID 是 1:

创建 4 个调色板,并记下它们的 ID。
这里,秋季调色板的 ID 是 17:

创建脚本

在你的服务器上 安装 Ruby

创建一个 seasons.rb 文件。在本示例中,我假设它位于 ~/scripts/ 目录下。

将以下内容放入该文件中。我们将向主题端点发送一个 PUT 请求,并包含颜色方案 ID 的负载:

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

current_month = Date.today.month
color_scheme_id = case current_month
                  when 1..3 then 18 # 冬季
                  when 4..6 then 15 # 春季
                  when 7..9 then 16 # 夏季
                  else           17 # 秋季
                  end

uri = URI('https://your-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' => 'YOUR_API_KEY',
  'Api-Username' => 'YOUR_USERNAME',
  'Content-Type' => 'application/json'
})

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

response = http.request(request)

替换以下内容:

  • your-discourse.com 为你的论坛域名
  • YOUR_API_KEY 为你的 API 密钥
  • YOUR_USERNAME 为 API 密钥所选的用户名
  • THEME_ID 为你主题的 ID。你可以在主题设置页面 URL 的末尾找到它。
    例如,在 https://your-discourse.com/admin/customize/themes/38 中,主题 ID 是 38

让我们手动测试一下脚本。
首先,如果尚未设置,请在 Discourse 界面中将主题设置为非季节性颜色方案。

然后,使用以下命令运行脚本:

ruby ~/scripts/seasons.rb

刷新浏览器。你主题使用的颜色方案应该会发生变化。:slight_smile:

最后一步是创建一个 cron 任务,在每个季节开始的第一天运行此脚本。

如果你不记得如何创建 cron 任务,可以回顾一下 第一个示例

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

完成!你的论坛现在将在每个新季节开始时呈现新的颜色!:sunny: :partying_face:

在 Web 服务器上接收 Web 请求,并使用其数据更新 Discourse 主题

这个示例更复杂一些!:technologist:

我们的工具是 PHP,这意味着我们假设你在某处有一个已安装 PHP 并正常运行的 Web 服务器。

在本示例中,我们将在一个 PHP 页面上接收来自 Ko-Fi(一个捐赠服务)的 Webhook 负载,然后利用接收到的数据调用 Discourse API,更新主题的标题和内容。

具体来说,它将用捐赠金额和日期更新主题标题,并在列出以往捐赠的表格中添加一行(甚至会自动提升该主题 :shushing_face:):

每次用户进行捐赠时,Ko-Fi[2] 都会向我们的 PHP 脚本发送请求。

配置 Ko-Fi

我在 Ko-Fi Webhooks 页面 上进行了配置,只需添加我的 PHP 文件 URL,并在高级部分记下隐藏的验证令牌。

对于单次捐赠,Ko-Fi 会向我们的 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
}

我们将接收此负载,然后提取我们需要的两个信息:

  • 金额 (3.00),我们将将其四舍五入为整数。

  • 时间戳 (2023-10-19T13:35:06Z),我们将将其格式化为更美观的日期。

接收 Ko-Fi 的负载

首先,我们在 PHP 页面中放置以下代码,以接收来自 Ko-Fi 的请求,确保我们收到的是 POST 请求,并且令牌值与 Ko-Fi Webhooks 页面中提供的匹配。我们还按照前述方式格式化金额和日期。

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

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

替换:

  • YOUR_VERIFICATION_TOKEN 为 Ko-Fi 提供的令牌

更新主题标题

下一步是更新我们的主题标题。我们将在 PHP 脚本中使用 curl 向正确的端点发送 PUT 请求。

        $putData = json_encode(['title' => '🥳 新捐赠:' . $amount . '€ on ' . $date]);
        $ch = curl_init('https://your-discourse.com/t/test-new-topic/TOPIC_ID');
        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: YOUR_API_KEY',
            'Api-Username: YOUR_USERNAME'
        ]);
        curl_exec($ch);

替换:

  • your-discourse.com 为你的论坛域名
  • TOPIC_ID 为正确的主题 ID
  • YOUR_API_KEY 为你的 API 密钥
  • YOUR_USERNAME 为 API 密钥所选的用户名

更新帖子内容

为了能够在主题的第一个帖子中追加新内容,我们需要首先通过 GET 请求检索其当前内容。

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

替换:

  • POST_ID 为正确的帖子 ID[3]

最后,我们需要通过向表格中添加一行(包含金额和日期)来更新帖子内容。我们将通过 PUT 请求完成此操作。

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

替换:

  • your-discourse.com 为你的论坛域名
  • POST_ID 为正确的帖子 ID
  • YOUR_API_KEY 为你的 API 密钥
  • YOUR_USERNAME 为 API 密钥所选的用户名

最终代码如下:

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

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

        $putData = json_encode(['title' => '🥳 新捐赠:' . $amount . '€ on ' . $date]);
        $ch = curl_init('https://your-discourse.com/t/test-new-topic/TOPIC_ID');
        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: YOUR_API_KEY',
            'Api-Username: YOUR_USERNAME'
        ]);
        curl_exec($ch);

        $ch_get = curl_init('https://your-discourse.com/posts/POST_ID.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://your-discourse.com/posts/POST_ID');
        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: YOUR_API_KEY',
            'Api-Username: YOUR_USERNAME'
        ]);
        curl_exec($ch_put);

        curl_close($ch);
        curl_close($ch_get);
        curl_close($ch_put);
    } else {
        http_response_code(403);
        echo "无效的验证令牌。";
    }
} else {
    http_response_code(405);
    echo "仅允许 POST 请求。";
}
?>

让我再次强调本指南开头的警告 :stuck_out_tongue:

:warning: 本指南中的所有代码示例并非旨在展示最佳实践,也不建议直接照搬使用。
为了专注于 API 的使用,我们有意忽略或省略了许多检查、错误处理等内容。

现在我们可以从 Ko-Fi 触发测试请求,看看它如何更新我们的主题,包括标题和内容。:slight_smile:

就是这样!
你拥有了一个主题,每当有人在 Ko-Fi 上进行捐赠时,它都会被更新并提升!:partying_face:


:information_source: 本主题为 Wiki。欢迎随时纠正你发现的任何错误,并讨论如何改进本指南。


  1. 在此上下文中指特定的 URL。例如:https://your-discourse.com/posts.json ↩︎

  2. 关于其 API 的一些信息:https://help.ko-fi.com/hc/en-us/articles/360004162298-Does-Ko-fi-Have-an-API-or-Webhook- ↩︎

  3. 帖子 ID 可以在 HTML 代码中找到。它是一个带有以下属性的 <article> 元素:data-post-id="POST_ID" ↩︎

10 个赞

这太棒了@Canapin,而且我认为这是非常需要的。我之前一直在找这样的东西。谢谢!:slight_smile:

3 个赞

如何指定子主题?
如果我有一个名为 AutoDoc 的子主题的 jBASE,我是否应该用某个分隔符(jBASE>AutoDoc)将两者合并到主题中,还是有一个类别标签?

我明白了。当您在类别或子类别页面上时,URL会显示#而不是类别名称。由于子类别有自己的编号,因此您不必进行任何合并。

如何用更新的信息替换文章?

目前,我得到的是
{“action”:“create_post”,“errors”:[“标题已被使用”]}
而不是成功的更新。

难道没有其他用于更新帖子的操作吗?

这是响应文本。请求的 curl 没有指定操作。

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

如果您使用端点来更新主题,会怎样?

或者也许更新帖子:

我没看到。抓得好。我会试试的。谢谢。

更新:我还是漏掉了什么。看起来唯一的区别是添加了一个 edit_reason。我试过了,但没有效果。

这是完整的 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 个赞

要更新主题或帖子,您应该改用 PUT 方法!

正如 Firepup 所指出的,如果您希望更新帖子的内容,可以使用以下 API:Discourse API Docs

问题在于 PUT 请求需要 ID#,但我没有这些 ID。
当我 POST 新主题时,我会收集 #,但这个数字似乎不起作用。
当我使用浏览器查看主题时,它显示一个不同的 #,但这个数字似乎也不起作用。

例如:我生成了一个主题,POST 事件返回 {“id”:3244,…}
访问它的 URL 显示 …test-pl-auto-doc-fun/2803

所以,我发送了这个 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}”

然后我收到了“未找到页面”的 HTML 响应。

应该是 /posts/3244.json

你从那个 POST 请求中得到的 id 是帖子的 ID(第一个帖子的 ID);它在所有帖子中都是唯一的。

指南中的两个视频似乎都返回了 404。

1 个赞

API 是否可用于调用 AI 助手?

我不这么认为,因为 docs.discourse.org 没有提到它。不过,我也许是错的。

为什么应该通过 API 使用 AI 助手 :thinking:

构建一个连接到我的网站的机器人,该机器人连接到我拥有七年知识的论坛,以回答问题。
或者构建一个可以响应电子邮件的机器人,该机器人连接到我拥有七年知识的论坛,以回答问题。

那么 ai-bot 可能更符合您的需求。ai-helper 则是在阅读和撰写帖子时提供帮助。

正如注释所述,这并非全部列表。

注意:对于任何未列出的端点,您可以遵循 逆向工程 Discourse API 指南来找出如何使用 API 端点。

2 个赞

您可以通过 API 完成任何您可以通过 UX 完成的操作。逆向工程 Discourse API

API 会不断添加和更改内容。我发现直接查看浏览器中实际发生的情况更容易。

5 个赞

好主意,谢谢!