首页
/ RealWorld 后端 API 端点规范全解:Conduit 的 18 个 REST 接口、认证模型与官方测试验证

RealWorld 后端 API 端点规范全解:Conduit 的 18 个 REST 接口、认证模型与官方测试验证

2026-09-04 17:09:36作者:庞队千Virginia

RealWorld("The mother of all demo apps")为所有后端实现定义了一套统一的 API 契约,本文以仓库中的端点规范文档为核心,完整梳理认证头约定、用户/文章/评论/收藏/标签五大类共 18 个端点的请求与响应约定、查询参数与字段要求,并结合仓库内的 OpenAPI 规范、Hurl/Bruno 测试套件说明如何对本地实现做端到端自动化验证。读完后你可以直接按此契约实现一个 RealWorld 兼容的 Conduit 风格后端,并用官方测试脚本检验其正确性。

1. 认证头约定:Authorization: Token ...

RealWorld 的受保护接口统一通过请求头携带 JWT 令牌,规范文档给出的标准形式为:

Authorization: Token jwt.token.here
  • 令牌来自注册(POST /api/users)或登录(POST /api/users/login)成功后的响应中的 user.token 字段;
  • 该约定在 OpenAPI 规范中对应 apiKey 类型的 securityScheme,其描述明确要求“访问受保护资源时,必须已通过注册或登录获得有效 JWT,并通过 Authorization 头传入”(见 openapi.yml 第 912 行起的 securitySchemes 定义);
  • 官方 Hurl 测试中每个需要认证的请求都写成 Authorization: Token {{token}}(见 specs/api/hurl/auth.hurl 第 42 行起),这正是实现时需要对齐的格式。

2. 用户与认证端点(4 个)

2.1 登录:POST /api/users/login

无需认证,请求体示例(来自 endpoints.md):

{
  "user":{
    "email": "jake@jake.jake",
    "password": "jakejake"
  }
}

必填字段:emailpassword。成功返回一个 User 对象(结构见第 7 节)。OpenAPI 规范中该操作为 Login,成功状态码为 200,错误分支包括 401(凭据无效)与 422(字段校验失败,见 openapi.yml 第 22 行起)。

2.2 注册:POST /api/users

无需认证,请求体示例:

{
  "user":{
    "username": "Jacob",
    "email": "jake@jake.jake",
    "password": "jakejake"
  }
}

必填字段:emailusernamepassword,成功返回 User。从 openapi.yml 第 39 行起的 CreateUser 定义可以看出,注册成功的状态码是 201(而非 200),用户名或邮箱冲突时返回 409 Conflict——实现时注意区分这两个状态码,Hurl 测试中的断言也是 HTTP 201(见 specs/api/hurl/auth.hurl 第 1 行起)。

2.3 获取当前用户:GET /api/user

需要认证,返回当前登录用户对应的 User 对象。对应 OpenAPI 中的 GetCurrentUser

2.4 更新用户:PUT /api/user

需要认证,请求体示例:

{
  "user":{
    "email": "jake@jake.jake",
    "bio": "I like to skateboard",
    "image": "https://i.stack.imgur.com/xHWG8.jpg"
  }
}

接受的字段:emailusernamepasswordimagebio

从源码结构看,测试套件对更新接口的约束远比“字段可传”严格,specs/api/hurl/errors_auth.hurl 覆盖了以下边界行为:

  • email/username/password 传空字符串应被拒绝(422);
  • password 必须至少 8 个字符(18 字符以下简单短密码会被拒,64 字符长密码应接受);
  • 可空字段 bioimage 传空字符串时应规范化为 null 并持久化;显式传 null 对可空字段是合法操作。

这些行为对实现中的“空串归一化”逻辑(如 ORM 序列化前把 "" 转成 None)提出了明确要求。

3. 个人主页与关注端点(3 个)

3.1 获取个人主页:GET /api/profiles/:username

认证可选(游客可访问,登录后 following 字段才有意义),返回 Profile 对象。用户不存在时返回 404

3.2 关注用户:POST /api/profiles/:username/follow

3.3 取消关注:DELETE /api/profiles/:username/follow

两者均需要认证、无额外请求参数,成功时返回操作后的 Profile 对象;目标用户不存在时返回 404(对应 OpenAPI 中 FollowUserByUsername / UnfollowUserByUsername,见 openapi.yml 第 112 行起)。Hurl 测试 specs/api/hurl/profiles.hurl 验证了 follow 后 following: true、unfollow 后回落为 false 的持久化语义。

4. 文章端点(7 个)

文章是 RealWorld 数据模型的核心,端点最多。

4.1 文章列表:GET /api/articles

默认全局返回最新文章;支持以下查询参数(均见 endpoints.md):

参数 作用 示例 默认值
tag 按标签过滤 ?tag=AngularJS 不过滤
author 按作者用户名过滤 ?author=jake 不过滤
favorited 过滤某用户收藏的文章 ?favorited=jake 不过滤
limit 限制返回条数 ?limit=20 20
offset 跳过条数(分页游标) ?offset=0 0

认证可选,按最新创建时间降序返回 多篇文章articles 数组 + articlesCount)。limit/offset 两个参数在 OpenAPI 中定义为共享参数(openapi.yml 第 895 行起的 offsetParamlimitParam),分页行为由 specs/api/hurl/pagination.hurl 验证:limit=1 时先返回最新一篇,offset=1 后翻页拿到次新一篇。

4.2 关注流:GET /api/articles/feed

支持同样的 limitoffset 参数,必须认证,返回当前用户所关注用户发布的文章,按最新优先排序。specs/api/hurl/feed.hurl 验证了“新用户 feed 为空 → 关注后 feed 出现其文章”的完整链路。

4.3 获取单篇文章:GET /api/articles/:slug

无需认证,按 slug 返回 单篇文章;slug 不存在返回 404

4.4 创建文章:POST /api/articles

需要认证,请求体示例:

{
  "article": {
    "title": "How to train your dragon",
    "description": "Ever wonder how?",
    "body": "You have to believe",
    "tagList": ["reactjs", "angularjs", "dragons"]
  }
}

必填字段:titledescriptionbody;可选字段 tagList(字符串数组)。标题/描述/正文任一为空字符串时返回 422(对应 specs/api/hurl/errors_articles.hurl 中的 09–11 组断言)。

4.5 更新文章:PUT /api/articles/:slug

需要认证,可传可选字段 titledescriptionbodytitle 变更时 slug 也必须随之重新生成。请求体示例:

{
  "article": {
    "title": "Did you train your dragon?"
  }
}

规范对 slug 的约定值得特别注意(原文档原文):

slug 是文章的 URL 标识符。规范只要求它必须是唯一字符串,用于 fetch/update/delete 文章——重复标题也必须产生不同的 slug。如何派生由实现自定(常见做法是 title 的 kebab-case),测试套件不强制任何特定格式。

从源码结构看,specs/api/hurl/errors_articles.hurl 中专门有两组用例:12-duplicate-titles-are-allowed-each-gets-a-unique-slug(两个相同标题的文章各自获得不同 slug)与 13-update-article-without-taglist-tags-should-be-preserved(更新时不传 tagList 应保留原有标签;传空数组则清空标签;tagListnull 会被拒绝)——这些都是纯靠读接口列表容易漏掉的持久化细节。

4.6 删除文章:DELETE /api/articles/:slug

需要认证,且只能删除自己的文章:他人删除应返回 403specs/api/hurl/errors_authorization.hurl04-user-b-tries-to-delete-403 用例验证)。slug 不存在返回 404

5. 评论端点(3 个)

5.1 发表评论:POST /api/articles/:slug/comments

需要认证,请求体示例:

{
  "comment": {
    "body": "His name was my name too."
  }
}

必填字段:body;成功返回创建后的 Comment 对象。文章不存在或 body 为空分别返回 404/422

5.2 获取文章评论:GET /api/articles/:slug/comments

认证可选,返回 多条评论

5.3 删除评论:DELETE /api/articles/:slug/comments/:id

需要认证。权限语义为“谁评论的谁删”:非作者删除他人评论返回 403 且评论必须仍然存活(specs/api/hurl/errors_authorization.hurl07/08 用例显式验证了这一点);specs/api/hurl/comments.hurl 中还包含“选择性删除”场景——删掉一条后另一条仍然存在。

6. 收藏与标签端点(3 个)

6.1 收藏文章:POST /api/articles/:slug/favorite

6.2 取消收藏:DELETE /api/articles/:slug/favorite

均需要认证、无额外参数,成功返回 Article 对象——注意返回的是操作后的完整文章对象,favoritedfavoritesCount 应已更新。specs/api/hurl/favorites.hurl 验证了收藏状态持久化,以及第 2 节提到的 ?favorited=jake 过滤能力。

6.3 获取标签列表:GET /api/tags

无需认证,返回字符串数组:

{
  "tags": [
    "reactjs",
    "angularjs"
  ]
}

7. 响应对象结构速查

端点规范中的“返回 User / Profile / Article / Comment”均指向统一的响应格式文档(api-response-format.md),关键点:

  • Useremailtokenusernamebioimagebio/image 可为 null);
  • Profileusernamebioimagefollowing
  • Single ArticleslugtitledescriptionbodytagListcreatedAtupdatedAtfavoritedfavoritesCount,并内嵌 author Profile;
  • Multiple Articlesarticles 数组 + articlesCount
  • CommentidcreatedAtupdatedAtbody + 内嵌 author Profile。

响应头需保证 Content-Type: application/json; charset=utf-8

一个重要的版本行为变更(原文档标注):自 2024-08-16 起,GET /api/articlesGET /api/articles/feed 不再返回文章的 body 字段(性能考虑)。因此列表接口返回的文章对象没有 body,只有单篇接口才有完整正文——实现时不要在这两个列表端点输出 body

8. 错误码约定

端点失败时的状态码语义在 error-handling.md 中统一定义:

  • 422:字段校验失败,错误体形如 {"errors": {"body": ["can't be empty"]}}(字段名为键、错误消息数组为值);
  • 401:需要认证但未提供;
  • 403:请求合法但当前用户无权限;
  • 404:资源不存在。

这套语义在各分类的 Hurl 错误测试目录中逐条落实,可作为实现后的对照清单:specs/api/hurl/ 下的 errors_auth.hurlerrors_articles.hurlerrors_authorization.hurlerrors_comments.hurlerrors_profiles.hurl

9. 用官方测试套件验证你的实现

规范文档的 Introduction(introduction.md)明确:OpenAPI 规范与 Hurl 测试才是契约的最终权威,散文式文档与测试不一致时,以测试为准。

仓库提供了两套可直接对本地后端运行的测试:

Hurl 方式(Hurl 文件是唯一事实来源,见 specs/api/README.md):

HOST=http://localhost:3000/api ./run-api-tests-hurl.sh

run-api-tests-hurl.sh 内部以 hurl --test --jobs 1 串行执行 hurl/ 目录下全部用例,并注入两个变量:

  • host:API 基地址(脚本默认值为 http://localhost:8000,通常按 READMEHOST 环境变量覆盖);
  • uid:默认取时间戳+进程号,用于生成互不冲突的用户名/邮箱,保证同一后端可重复运行测试。

Bruno 方式(交互式集合,由 Hurl 自动生成并保持同步):

HOST=http://localhost:3000/api ./run-api-tests-bruno.sh

也可以直接用 Bruno 打开 specs/api/bruno/ 目录逐请求调试。按 specs/api/README.md 说明,Bruno 集合通过 make bruno-generate 从 Hurl 生成,并经 CI 以 make bruno-check 保持同步,因此两套集合的覆盖面一致。

10. 小结

RealWorld 的后端契约由三部分构成:端点清单(18 个接口,覆盖认证、用户、个人主页、关注、文章、评论、收藏、标签)、统一响应对象格式(User/Profile/Article/Comment/Tags)与四类状态码语义(422/401/403/404)。实现时的重点难点集中在:注册返回 201、更新用户时 bio/image 空串归一化为 null、文章标题变更后重新派生 slug 且重复标题必须 slug 唯一、列表接口自 2024-08-16 起不再输出 body、以及各类越权操作的 403/404 精确区分。以 specs/api/openapi.yml 为机器可读契约、以 specs/api/hurl/ 测试套件为验收基准,即可交付一个完全兼容 RealWorld 规范的 Conduit 后端。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.79 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
988
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384