建议
本节包含 JSON:API 实现的建议。这些建议旨在为超出 JSON:API 规范范围的领域建立一致性。
命名
规范对 JSON:API 文档中成员(即键)的命名方式施加了一定的 硬性限制。为了进一步标准化成员名称,这在混合来自不同方撰写的配置文件时尤为重要,以下规则也建议使用
- 成员名称 **应** 使用驼峰式命名法(即
wordWordWord
) - 成员名称 **应** 以 “a-z” (U+0061 到 U+007A) 字符开头和结尾
- 成员名称 **应** 只包含 ASCII 字母数字字符(即 “a-z”、”A-Z” 和 “0-9”)
URL 设计
参考文档
在确定 API 的 URL 结构时,需要考虑所有资源都存在于单个 “参考文档” 中,其中每个资源都可以在唯一的路径下访问。资源在该文档的顶层按类型进行分组。单个资源在这些类型化的集合中按 ID 索引。单个资源内的属性和链接根据上述资源对象结构进行唯一寻址。
参考文档的概念用于确定资源以及其关系的适当 URL。重要的是要理解,此参考文档的结构与用于传输资源的文档略有不同,因为它们的目标和约束不同。例如,参考文档中的集合表示为集合,因为成员必须通过 ID 寻址,而传输文档中的集合表示为数组,因为顺序很重要。
资源集合的 URL
建议资源集合的 URL 由资源类型组成。
例如,类型为 photos
的资源集合将具有 URL
/photos
单个资源的 URL
将资源集合视为按资源 ID 索引的集合。单个资源的 URL 可以通过将资源的 ID 附加到集合 URL 来形成。
例如,ID 为 "1"
的照片将具有 URL
/photos/1
关系 URL 和相关资源 URL
正如基本规范中所述,每个关系可以公开两个 URL
-
“关系 URL” - 关系本身的 URL,在关系的
links
对象中使用self
键标识。此 URL 允许客户端直接操作关系。例如,它将允许客户端从post
中移除author
,而无需删除people
资源本身。 -
“相关资源 URL” - 相关资源的 URL,在关系的
links
对象中使用related
键标识。当获取时,它将相关资源对象作为响应的主要数据返回。
建议将关系 URL 构成,方法是在资源的 URL 后附加 /relationships/
和关系的名称。
例如,照片的 comments
关系将具有 URL
/photos/1/relationships/comments
而照片的 photographer
关系将具有 URL
/photos/1/relationships/photographer
建议将相关资源 URL 构成,方法是在资源的 URL 后附加关系的名称。
例如,照片的 comments
的 URL 将为
/photos/1/comments
而照片的 photographer
的 URL 将为
/photos/1/photographer
由于这些 URL 表示关系中的资源,因此不应将其用作资源本身的 self
链接。相反,在形成 self
链接时,应继续使用单个资源 URL 的建议。
过滤
基本规范对服务器支持的过滤策略保持中立。 filter
查询参数系列保留用作任何过滤策略的基础。
建议希望根据关联关系对资源集合进行过滤的服务器通过允许组合 filter
与关联关系名称的查询参数来实现此目的。
例如,以下是请求与特定帖子相关联的所有评论的请求
GET /comments?filter[post]=1 HTTP/1.1
多个过滤值可以组合在逗号分隔的列表中。例如
GET /comments?filter[post]=1,2 HTTP/1.1
此外,可以将多个过滤器应用于单个请求
GET /comments?filter[post]=1,2&filter[author]=12 HTTP/1.1
包含顶级、资源级和关系链接
基本规范对在资源响应中包含链接保持中立。但是,建议在响应文档中包含以下链接
- 顶级链接,如自链接(对于整个响应)以及相对分页链接(如果适用)。
- 资源级链接,如每个资源的自链接(如果资源是集合的一部分,则与顶级链接不同)。
- 关系链接,用于资源的所有可用关系。
例如,对评论集合的请求可能提示以下响应
GET /comments HTTP/1.1
{
"data": [{
"type": "comments",
"id": "1",
"attributes": {
"text": "HATEOS are the thing!"
},
"links": {
"self": "/comments/1"
},
"relationships": {
"author": {
"links": {
"self": "/comments/1/relationships/author",
"related": "/comments/1/author"
}
},
"articles": {
"links": {
"self": "/comments/1/relationships/articles",
"related": "/comments/1/articles"
}
}
}
}],
"links": {
"self": "/comments"
}
}
支持缺乏 PATCH
的客户端
某些客户端(如 IE8)缺乏对 HTTP 的 PATCH
方法的支持。希望支持这些客户端的 API 服务器建议在客户端包含 X-HTTP-Method-Override: PATCH
标头的情况下,将 POST
请求视为 PATCH
请求。这允许缺乏 PATCH
支持的客户端通过简单地添加标头来完成更新请求。
格式化日期和时间字段
尽管 JSON:API 未指定日期和时间字段的格式,但建议服务器与 ISO 8601 保持一致。 此 W3C 注解 提供了推荐格式的概述。
异步处理
考虑需要创建资源且操作需要很长时间才能完成的情况。
POST /photos HTTP/1.1
请求 **应** 返回状态 202 Accepted
,并在 Content-Location
标头中包含一个链接。
HTTP/1.1 202 Accepted
Content-Type: application/vnd.api+json
Content-Location: https://example.com/photos/jobs/5234
{
"data": {
"type": "jobs",
"id": "5234",
"attributes": {
"status": "Pending request, waiting other process"
},
"links": {
"self": "/photos/jobs/5234"
}
}
}
要检查作业处理的状态,客户端可以向之前提供的地址发送请求。
GET /photos/jobs/5234 HTTP/1.1
Accept: application/vnd.api+json
对仍处于挂起状态的作业的请求 **应** 返回状态 200 OK
,因为服务器已成功报告状态。可选地,服务器可以返回 Retry-After
标头,以指导客户端应等待多长时间才能再次检查。建议重试时间早于 1 秒,可以使用 Retry-After: 0
实现。
HTTP/1.1 200 OK
Content-Type: application/vnd.api+json
Retry-After: 10
{
"data": {
"type": "jobs",
"id": "5234",
"attributes": {
"status": "Pending request, waiting other process"
},
"links": {
"self": "/photos/jobs/5234"
}
}
}
作业处理完成后,请求 **应** 返回状态 303 See other
,并在 Location
标头中包含一个链接。
HTTP/1.1 303 See other
Content-Type: application/vnd.api+json
Location: https://example.com/photos/4577
撰写配置文件
配置文件是一种机制,可以由文档的发送者使用,以对文档的内容做出承诺,而不会添加或更改 JSON:API 规范的基本语义。例如,配置文件可能表明所有资源对象都将具有 timestamps
属性字段,并且 timestamps
对象的成员将使用 ISO 8601 日期时间格式进行格式化。
配置文件是对这些承诺的独立规范。以下示例说明了如何撰写上述配置文件
# Timestamps profile
## Introduction
This page specifies a profile for the `application/vnd.api+json` media type,
as described in the [JSON:API specification](https://jsonapi.fullstack.org.cn/format/).
This profile allows every resource in a JSON:API document to represent
significant timestamps in a consistent way.
## Document Structure
Every resource object **MUST** include a `timestamps` member in its associated
`attributes` object. If this member is present, its value **MUST** be an object that
**MAY** contain at least one of the following members:
* `created`
* `updated`
The value of each member **MUST** comply with the variant of ISO 8601 used by
JavaScript's `JSON.stringify` method to format Javascript `Date` objects.