☰
HTTP API 设计指南:在请求体中接受序列化 JSON(Accept Serialized JSON in Request Bodies)
2026/10/6 12:29:28 网站建设 项目流程
  • API设计
  • 教程

【免费下载链接】http-api-design

HTTP API design guide extracted from work on the Heroku Platform API

项目地址:https://gitcode.com/gh_mirrors/ht/http-api-design
点击查看免费下载

本文是 http-api-design(原 Heroku Platform API 设计实践提炼的 HTTP+JSON API 设计指南)中 Requests 章节的核心条目之一。它回答了一个 API 设计者绕不开的问题:客户端在POST/PUT/PATCH请求中应当以什么格式提交数据。读完本文,你将掌握 JSON 请求体相对于传统表单编码(form-encoded)的优势、Content-Type头的正确用法、请求体与响应体之间的对称设计原则,以及在本仓库其他章节中与之配套的属性命名、资源标识与类型约束约定。

一、核心原则:请求体与响应体保持对称

现代 HTTP+JSON API 的响应体几乎毫无例外地采用 JSON 序列化格式,这一点在 en/responses/README.md 一节的多个条目中都有体现,例如 Keep JSON minified in all responses 要求响应保持精简、Provide standard response types 规定了 JSON 各基本类型的取值范围。

本条目主张的是:请求方向同样应当接受序列化 JSON,在PUT/PATCH/POST请求体中,让 JSON 替代或补充 form-encoded 数据。这样做的直接收益是形成请求-响应两端的"对称性"(symmetry):

  • 客户端发送的是 JSON,服务端返回的也是 JSON,同一种序列化心智贯穿整个请求/响应生命周期;
  • 请求体的结构与响应体结构天然对齐(例如提交owner对象与读取owner对象使用相同的嵌套表达);
  • 避免了同一资源在"写入用表单、读取用 JSON"之间的双向映射成本,减少序列化器与字段名转换的出错面。

原文档给出的完整示例(en/requests/accept-serialized-json-in-request-bodies.md):

$ curl -X POST https://service.com/apps \ -H "Content-Type: application/json" \ -d '{"name": "demoapp"}' { "id": "01234567-89ab-cdef-0123-456789abcdef", "name": "demoapp", "owner": { "email": "username@example.com", "id": "01234567-89ab-cdef-0123-456789abcdef" }, ... }

注意示例中两个关键细节:请求通过Content-Type: application/json显式声明载荷类型;而响应中的id字段是 UUID 格式的字符串,这与 Provide resource (UU)IDs 条目关于资源标识符的要求保持一致。

二、Content-Type:如何声明请求体的媒体类型

要让服务端正确解析 JSON 请求体,客户端必须在请求头中声明媒体类型。原示例使用的是:

Content-Type: application/json

这是 JSON 请求体最标准的媒体类型(media type)。若服务端需要区分不同的 JSON 结构变体,可在该类型后附加参数,例如application/json; charset=utf-8显式声明字符集。

在设计 API 时,服务端应对Content-Type做出如下决策:

  • 只接受 JSON:严格校验Content-Type: application/json,对application/x-www-form-urlencoded或其他类型返回415 Unsupported Media Type;
  • JSON 优先、表单兼容:同时支持两种媒体类型,但文档中明确推荐 JSON 作为首选交互方式,表单编码仅作为旧客户端的兼容通道;
  • 不要静默猜测:当请求体存在但Content-Type缺失或无法解析时,应返回明确的错误,避免凭内容猜测类型导致歧义。这一点与 Generate structured errors 的结构化错误设计思路一致——解析失败也应返回可机器读取的错误结构。

三、path / body / headers:请求各部分的关注点分工

JSON 请求体之所以可行,前提是请求的各个部分各司其职。Separate concerns 条目给出了这套分工的权威表述:

  • path 表示身份:URL 路径用于定位要操作的具体资源或集合;
  • body 传递内容:请求体承载资源的属性数据(即本条目所说的序列化 JSON);
  • headers 传递元数据:Content-Type、Accept、认证信息、版本信息等通过请求头表达;
  • query params 仅作边缘补充:在特殊情况下可用于传递本应放在 header 中的信息,但 header 更灵活、能承载更多样的信息,因此是首选。

把这三者关系落到本条目上就是:POST /apps中的/apps(path)指出要创建的是哪个集合上的资源,{"name": "demoapp"}(body)描述该资源的完整内容,Content-Type: application/json(header)告诉服务端如何解读 body。三者缺一不可,彼此职责清晰,这正是"关注点分离"在请求侧的具体应用。

四、请求体 JSON 的结构设计要点

接受 JSON 请求体之后,字段本身的设计同样要遵循本仓库 Requests 与 Responses 章节的约定:

4.1 属性名:小写 + 下划线分隔

Downcase paths and attributes 要求属性名使用小写字母与下划线分隔,例如:

{ "name": "demoapp", "service_class": "first" }

这样做的原因是下划线分隔的属性名在 JavaScript 中可以不加引号直接作为对象键书写,同时与 URL 路径中的小写规范(service-api.com/users、service-api.com/app-setups)保持整体一致。

4.2 属性类型:遵循标准响应类型约束

请求体中的每个字段应遵循 Provide standard response types 对 JSON 基本数据类型的取值约束:

  • String:字符串或null;
  • Boolean:仅true/false;
  • Number:数值或null,注意精度超过 15 位小数的数值需以字符串传递,避免某些 JSON 解析器将长精度数字转为字符串导致类型不稳定;
  • Array:始终为数组,无值时返回/提交空数组[]而不是null;
  • Object:对象或null。

这些约束同时适用于请求体与响应体,保证了同一字段在"提交"与"返回"两个方向上的类型一致性。

4.3 嵌套对象:与外键关系表达一致

请求体中允许嵌套对象(如示例中的owner),这与 Nest foreign key relations 在响应侧鼓励嵌套外键关系的做法相呼应,使读写两端的资源结构尽量对齐。

4.4 资源标识:可接受 ID 或名称

当客户端需要引用已有资源时,Support non-id dereferencing for convenience 建议同时接受 UUID 与人类可读的名称(如 Heroku 的应用名),但不允许只接受名称而排斥 ID。这意味着请求体中引用其他资源的字段(例如parent_app)在设计时也可以遵循同样的宽容策略。

五、操作语义:JSON 请求体与 HTTP 方法的配合

JSON 请求体通常配合POST/PUT/PATCH三种方法使用,其语义区别是:

  • POST:在集合上创建新资源(示例POST /apps即此用途),通常返回201 Created及完整资源;
  • PUT:整体替换指定资源;
  • PATCH:局部更新指定资源的若干字段。

Actions 条目同时提醒:应优先设计不需要特殊 action 的端点配置;确实需要动作语义时,用actions前缀显式区分(如/runs/{run_id}/actions/stop)。将动作折叠为资源属性后,自然由POST/PATCH携带 JSON 请求体完成,而不是发明自定义的动词。

六、与服务端解析配套的工程注意点

从工程实现角度看,接受 JSON 请求体意味着服务端需要:

  1. 按 Content-Type 路由解析器:application/json走 JSON 反序列化,form-encoded 走表单解析,二者互不干扰;
  2. 限制请求体大小:JSON 通常比同义的表单数据更长,服务端应配置 body size 上限并返回明确错误(可参考 Return appropriate status codes 中的413 Payload Too Large语义);
  3. 校验必填字段与类型:请求体字段缺失或类型错误时返回结构化错误,而不是笼统的400;
  4. 结合版本化与安全约定:本仓库 Foundations 中的 Require Versioning in the Accepts Header 与 Require Secure Connections 等条目,为请求体的安全传输与向后兼容提供了配套基线。

七、小结

"在请求体中接受序列化 JSON"是一条看似简单、影响深远的设计决策。它的价值不在于炫技,而在于让 API 的读写两端共享同一种序列化心智,配合 Separate concerns 的 path/body/headers 分工,以及与响应侧 标准类型约束、UUID 资源标识、属性小写下划线命名 等约定的共同作用,最终形成一套自洽、一致、可预测的 HTTP+JSON API。设计新 API 时,把 JSON 请求体作为默认选择,把 form-encoded 视为兼容性备选,是一个稳妥且可持续的起点。

  • API设计
  • 教程

【免费下载链接】http-api-design

HTTP API design guide extracted from work on the Heroku Platform API

项目地址:https://gitcode.com/gh_mirrors/ht/http-api-design
点击查看免费下载
上一篇:如何把优酷、B站等7个平台的视频离线保存到本地?Video-Downloader 实操指南
下一篇:渔人的直感 FF14 钓鱼计时器:从 clone 到出鱼 5 分钟实测

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询