W weiserv
← 返回博客

用 REST API 让 AI Agent 帮你写博客:weiserv 博客自动化实践

背景:让内容生产可以"被调用"

个人技术站要持续产出内容,一个痛点是"写作→发布"的链路太手工。既然站点是 Django 写的,顺手用 Django REST Framework(DRF)做了一套博客管理 API,把"发文章"变成一次 HTTP 请求。这样 AI agent、定时任务、或其他系统都能通过标准接口管理博客,而不必登录后台手动粘贴 Markdown。

本文不堆砌 DRF 入门,而是聚焦接口契约设计安全边界取舍——这两点才是实战里容易翻车的地方。

接口概览

API 挂在 /api/v1/ 下,博客相关两个核心端点:

方法 路径 说明 鉴权
GET /api/v1/posts/ 列表(分页,匿名可见已发布) 公开
POST /api/v1/posts/ 创建文章 Token
GET /api/v1/posts/<slug>/ 详情 公开
PUT/PATCH /api/v1/posts/<slug>/ 全量/局部更新 Token
DELETE /api/v1/posts/<slug>/ 删除 Token
POST /api/v1/upload/ 图片上传(multipart,≤5MB) Token

列表默认按时间倒序,每页 20 条,响应形如 {"count":..., "next":..., "previous":..., "results":[...]}

鉴权:Token 怎么来、怎么带

接口用 DRF 的 TokenAuthentication。请求头这样带:

Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b

注意是 Token 不是 Bearer关键点:项目没有 token 签发端点(没注册 obtain_auth_token),Token 必须在服务器端用 manage.py shell 生成一次,妥善保存:

python manage.py shell -c \
  "from django.contrib.auth.models import User; \
   from rest_framework.authtoken.models import Token; \
   u=User.objects.get(username='admin'); \
   t,_=Token.objects.get_or_create(user=u); print(t.key)"

创建文章的字段约定(易错点)

curl -X POST "https://weiserv.com/api/v1/posts/" \
  -H "Authorization: Token $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "通过 REST API 发博",
    "slug": "rest-api-test-post",
    "excerpt": "用 DRF 接口发布的示例",
    "body": "## 正文\n\n这是 Markdown 正文。",
    "category": 1,
    "tags": ["Django", "API"],
    "published": true
  }'

三个容易踩的约定:

  1. category 传整数 ID,不是分类名。分类是 core.Category 表的外键,API 接收主键数字;传不存在的 ID 会返回 400 {"category":["Invalid pk ..."]}
  2. slug 唯一。重复创建直接 400 {"slug":["slug already in use"]}——API 不会像"草稿箱"那样静默跳过,调用方需自己保证 slug 不冲突(或用 PATCH 改已有文章)。
  3. published 是布尔true 即上线,false 即草稿。项目没有 status 枚举字段,就是这一个布尔开关。tags 传字符串数组,服务器端用 taggitset() 关联。

响应里 tags 以字符串数组返回,category_name 一并给出,方便调用方核对。

两条发博路径的安全边界

个人站其实有两条发博通道,区别在于鉴权模型和安全边界

维度 REST API(本文) 服务器端直发
通道 HTTPS 调公网 /api/v1/posts/ SSH 到服务器跑 Django 脚本
鉴权 Token,请求头携带 不需要 Token,靠 SSH 密钥
Token 是否进对话 (有泄露风险) 不出对话(最安全)
分类传参 整数 ID 分类名,get_or_create 自动建
幂等语义 slug 重复直接 400 已存在则跳过(SKIP)

对个人站来说,"Token 不进对话"是一条硬安全约定——所以我自己平时发博走的是服务器端直发(Token 全程不出现在任何对话里)。REST API 这条路更适合外部系统 / AI agent 通过标准 HTTP 集成的场景:调用方愿意自己保管 Token,且通常通过服务端程序(curl、后端任务)调用,而非浏览器。

补充一个 CORS(跨域资源共享)现状:当前只对 /api/ 路径启用 CORS 中间件,但没配跨域白名单。这意味着浏览器里从别的域名网页调这个 API 会被拦;但 curl、服务端到服务端、AI agent 这类不带 Origin 头的非浏览器调用完全不受影响。若将来要支持浏览器端第三方页面调用,才需要在 settings.pyCORS_ALLOWED_ORIGINS

小结

把"发博客"抽象成一个有清晰契约的 REST 接口,价值不在炫技,而在于让内容生产可被程序调度:agent 写完稿直接 POST 上线、定时任务批量维护、外部系统同步内容,都成了几行代码的事。设计时的两个核心取舍——Token 的保管边界字段契约(ID vs 名称、slug 唯一性、布尔 published)——决定了这套接口是"好用且安全"还是"能用但埋雷"。把这两点想清楚,自动化才真正可靠。

广告位占位 · post-inline