最新规范(v1.0)翻译

目前规范状态

目前规范的最新正式版本是1.0版本。新的JSON API规范会向后兼容,采取只增不减的策略。如果你有什么想补充的,可以在我们的论坛上提出来。

如果你发现规范错误或者你写了一个实现库,请在我们的Github仓库中,提一个issue或者创建pull request让我们知晓。

介绍

JSON API是一个前后端请求响应规范,描述了客户端应该如何获取和修改资源以及服务器应该如何对请求做出响应。

JSON API的设计目标是在不影响可读性、灵活性和可发现性的基础上,减少请求次数,降低前后端数据传输数量。

JSON API在交换数据时需要使用特有的媒体格式——application/vnd.api+json

约定

本文中的关键词“MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, “OPTIONAL”按RFC 2119[RFC2119]规范中的描述解释

内容协商

客户端权责

客户端必须(MUST)在所有请求报文上使用请求头Content-Type: application/vnd.api+json,而不带有其他任何的媒体类型参数。

客户端必须(MUST)在不包含任何媒体类型的情况下,在Accept请求头中至少指定JSON API媒体格式一次。

客户端在响应报文的Content-Type字段中必须(MUST)忽略除application/vnd.api+json媒体格式以外所有参数。

服务器端权责

服务器所有响应报文必须(MUST)带有响应头Content-Type: application/vnd.api+json, 而不带任何其他的媒体类型参数。

如果请求头中的Content-Type字段带有除application/vnd.api+json外的其他参数,服务器端必须(MUST)使用415 UnSupported Media Type状态码响应。

如果请求Accept头包含JSON API媒体类型,并且该媒体类型的所有实例均按媒体类型参数进行转换,则服务器必须(MUST)使用 406 NOT Acceptable 状态码响应。

注意:内容协商的存在是为了本规范的未来版本能使用媒体参数进行协商的扩展以及版本的控制。

文档结构

这个小节将描述由媒体类型application/vnd.api+json标识的JSON API 的文档结构。JSON API文档将会在JSON(RFC7159)中定义。

尽管请求和响应报文都使用同一个媒体类型,但是其实规范的某一方面可能是针对某一端的。这其中的区别会在下面进行阐述。

除非特殊说明,规范所定义的对象不能(MUST NOT)包含额外的内容。客户端和服务器端的实现必须忽略不能被规范识别的内容。

注意:这些条件使得本规范能够通过附加的变动进行扩展

Top Level

每个包含数据的JSON API请求和响应的顶层必须(MUST)是一个JSON对象。这个对象定义了文档的“top level”。

一个文档必须(MUST)包含至少一个top-level成员:

  • data :文档的“主要数据”

  • errors : 一个错误对象数组

  • meta : 一个元数据对象,包含了非标准的元数据信息

dataerrors 成员必须同时出现在相同的文档中。

一个文档可能(MAY)会包含以下的top-level成员:

  • jsonapi:一个描述服务器实现的对象

  • links:一个与主要数据相关链接对象。

  • included :一个与主要数据或者其他资源对象相关的资源对象数组

如果一个文档不包含data 键,那么included 成员也不能(MUST NOT)存在。

一个top-level的链接对象可能包含以下对象:

  • self :生成当前响应文档的链接

  • related : 关联资源链接(当主要数据显示的是资源关系的时候)

  • 主要数据的分页链接

文档的“主要数据”指的是请求所针对的资源或是资源集合。

主要数据必须(MUST)为以下的其中一种:

  • 对于针对单个资源的请求来说,是一个单独的资源对象,一个单独的资源标识符对象,或者null

  • 对于针对资源集合的请求来说,是一个资源对象数组,一个资源标识符对象数组,或是空数组([]

例如,下面的主要数据是一个单独的资源对象:

{
 "data": {
   "type": "articles",
   "id": "1",
   "attributes": {
     // ... this article's attributes
   },
   "relationships": {
     // ... this article's relationships
   }
 }
} 

下面的主要数据是一个资源标识对象和上面的数据代表同一资源

{
 "data": {
   "type": "articles",
   "id": "1"
 }
} 

逻辑资源的集合必须(MUST)表示为数组,即使只包含一个资源或是为空。

资源对象

“资源对象”在JSON API文档中表示资源。

一个资源对象必须(MUST)至少包含以下两个成员:

  • id

  • type

例外:对于在客户端上生成并在服务端被创建的资源对象 id 成员是不需要的。

另外,一个资源对象可能(MAY)包含以下顶级成员:

  • attributes :表示某些资源数据的属性对象

  • relationships : 描述资源与资源之间关系的关联对象

  • links : 包含与资源相关的链接的链接对象

  • meta : 一个元数据对象,包含了不能被表示为属性和关系的非标准元数据信息

这里有一个可能会在文档中出现的文章资源(即文章类型的资源)

// ...
{
 "type": "articles",
 "id": "1",
 "attributes": {
   "title": "Rails is Omakase"
 },
 "relationships": {
   "author": {
     "links": {
       "self": "/articles/1/relationships/author",
       "related": "/articles/1/author"
     },
     "data": { "type": "people", "id": "9" }
   }
 }
}
// ... 

标定

每一个资源对象必须(MUST)包含一个id 成员和一个type 成员。idtype 的值必须为字符串类型。

在一个给定的API中,每个资源对象的type  和id 必须(MUST)能够标定一个单独的,唯一的资源。(由一个服务器控制的URI集合或是由多个服务器作为一个整体输出的一个API)

type 成员被用于描述拥有相同属性及关系的资源对象。

type 成员的值必须(MUST)和成员名称遵循相同的约束。

注意:本规范不考虑变形规则,所以 type 值可以是单数也可以是复数。但是整个实现中必须使用相同的值。

字段

一个资源对象的属性及其关系可以统一称之为“字段”。

typeid 所标定的资源对象的字段必须和其它资源分享同一命名空间。换句话说,就是不能出现同名属性,而且不能有属性命名为typeid

属性

attributes 的值必须(MUST)是一个对象(一个“属性对象”)。属性对象表示了资源对象定义相关的信息。

属性可能包含任意的JSON值。

涉及复杂数据结构的JSON 对象和数组都可以是属性值。但是,组成或是包含在属性中的对象不能(MUST NOT)包含relationships 或是links 属性 ,因为这些属性是规范中的保留字、

对象中通常有外键和其他信息一起存储在内部,但是这些属性其实不应该(SHOULD NOT)作为属性出现。

注意:查看关于字段及成员名的更多限制

关联

relationships 属性值必须是一个对象(一个“关联对象”)。关联对象的成员们表示了资源对象之间关联的定义。

关联关系必须(MUST)是一对一或是一对多的。

一个“关联对象”必须包含至少一个以下成员:

  • links : 一个链接对象包含至少一个以下成员:

  • self : 关联关系本身的链接(一个关联链接)。这个链接允许客户端直接操作关联关系。例如,通过article 的关联关系URL移除author 将会从article 中移除people而不移除people 资源本身。当获取成功的时候,该链接会返回相关资源的连锁作为其主要数据。(参见获取关联关系)

  • related :一个关联资源链接

  • data : 资源连锁

  • meta : 一个元数据对象包含了关于关联关系的非标准元信息

一个表示一对多关系的关联对象可能(MAY)在links 成员也包含了分页链接。关联对象中的任何分页链接必须对关联数据进行分页,而不是对关联资源。

注意:查看关于字段及成员名的更多限制

相关资源链接

一个“相关资源链接”为资源对象的关联关系中已经定义的链接提供了访问。当被获取时,关联资源对象将会返回在响应体的主要数据中。

例如, articlecomments 关联可以表示为一个链接,通过 GET 请求返回comment资源对象集合。

如果存在,一个相关资源链接必须(MUST)引用一个有效的URL,即使关联关系现在和目标资源没有关联。此外,一个相关的资源链接不能(MUST NOT)因为关联关系的内容变化而变化。

资源连锁

复合文档中资源连锁允许客户端将所有被包含的资源对象全部整合在一起,且不用通过链接 GET 资源。

资源连锁必须(MUST)为以下几种方式:

  • 在一对一关系中如果为空,则为 null

  • 在一对多关系中为空,则为 []

  • 对于非空的一对一关系,则为单独的资源标识符对象

  • 对于非空的一对多关系,则为资源标识符对象数组

注意:本规范并没有规定资源标识符在一对多连锁数组的顺序有何含义,虽然实现库可能会赋予其相关含义。一个响应对象的资源标识符对象数组可能表示为有序或是无序亦或是两种方式的混合。

例如,下面的文章和 author 关联

// ...
{
 "type": "articles",
 "id": "1",
 "attributes": {
   "title": "Rails is Omakase"
 },
 "relationships": {
   "author": {
     "links": {
       "self": "http://example.com/articles/1/relationships/author",
       "related": "http://example.com/articles/1/author"
     },
     "data": { "type": "people", "id": "9" }
   }
 },
 "links": {
   "self": "http://example.com/articles/1"
 }
}
// ... 

author 关联关系中包含关联关系本省的链接(这使得客户端能够直接改变author关联),获取资源对象的关联资源链接,以及连锁信息。

资源链接

每个资源对象的可选属性links 包含了关联到资源的链接。

如果资源链接存在,那么链接对象可能(MAY)包含了 self 链接,指向当前资源对象。

// ...
{
 "type": "articles",
 "id": "1",
 "attributes": {
   "title": "Rails is Omakase"
 },
 "links": {
   "self": "http://example.com/articles/1"
 }
}
// ... 

当通过 GET 请求self链接的时候,服务器必须(MUST)返回和当前资源数据相同的数据。

资源标识符对象

“资源标识符对象”是一个指代了单独资源的对象。

“资源标识符对象”必须(MUST)包含 typeid 成员。

“资源标识符对象”可能也包含了meta 成员(包含非标准元信息的meta对象)。

复合文档(Compound Documents)

为了减少HTTP请求数量,服务器可能(MAY)允许和主要资源相关联的资源包含在响应体中。这样的响应体称之为“复合文档”。