Index

状态

这个页面是JSON API最新的发行版本,当前版本是1.0。新版本的JSON API使用不移除,只添加策略,永远是向后兼容的。可在论坛提出建议。

如果你发现了规范中的文本错误,或者你想参与到其中,请在GitHub repository提出公开的issue或者pull request来让我们知道。

介绍

是一个规范,它定义了客户端应该如何获取与修改资源,以及服务器应该如何响应客户端的请求。

JSON API 的设计尽可能减少请求量和客户端与服务器间传输的数据量。而且在实现高效的同时,无需牺牲可读性、灵活性和可发现性。

JSON API需要使用JSON API媒体类型(application/vnd.api+json) 进行数据交互。

约定

文档中的关键词,MUSTMUST NOTREQUIREDSHALLSHALL NOTSHOULDSHOULD NOTRECOMMENDEDMAYOPTIONAL的具体描述在RFC2119中。

附RFC 2119中对表示要求的动词的说明

  1. MUST 表示绝对要这样做,REQUIRED或者SHALL与其同义,在翻译时应统一译为:必须

  2. MUST NOT 表示绝对不要这样做,SHALL NOT与其同义,在翻译时应统一译为:不能

  3. SHOULD 表示一般情况下应该这样做,但是某些特定情况下可以忽视这个要求。RECOMMENDED与其同义,在翻译时统一译为:应该

  4. SHOULD NOT 表示一般情况下不应该这样做,但是在某些特定情况下可以忽视这个要求。NOT RECOMMENDED与之同义,在翻译时统一译为:不应该

  5. MAY 表示这个要求完全是可选的,你可以这样做,也可以不这样做。OPTIONAL与之同义,在翻译时统一译为:可以

内容协定

客户端的职责

客户端在发送JSON API数据的请求文档时,必须在HTTP头附加上Content-Type: application/vnd.api+json,但不能添加任何的媒体类型参数。

Accept头中包含了JSON API媒体类型的客户端必须至少指定一次媒体类型,但不能添加任何的媒体类型参数。

客户端在接收到Content-Type头含有application/vnd.api+json媒体类型的响应文档时,必须忽略其所有的参数。

服务器的职责

服务器发送的所有包含JSON API数据的文档必须在HTTP头中添加Content-Type: application/vnd.api+json,但不能添加任何的媒体类型参数。

服务器若收到了在指定Content-Type: application/vnd.api+json的同时,还包含了任意媒体类型参数的请求,必须返回415 Unsupported Media Type状态码。

服务器若收到了Accept头中含有JSON API或其他媒体类型,但却被媒体类型参数修改的请求时,必须返回406 Not Acceptable状态码。

说明:内容协定需要存在于该规范的将来的版本中,需要使用媒体参数来扩展协定或协商版本。

文档结构

这一章节描述JSON API文档结构,该结构通过媒体类型(application/vnd.api+json) 标识。JSON API文档使用JavaScript Object Notation[RFC7159]定义。

尽管请求和响应文档都使用同样的媒体类型,但某些特性只适用于其中一种。下面描述它们之间的差异。

除非另有说明,否则本规范中定义的对象不能包含任何附加的成员,客户端和服务器的实现也必须忽略规范不认可的成员。

说明:这些条件允许通过本规范通过累积修改来衍变。

顶层

每个JSON API请求或响应数据的根必须有一个JSON对象。这个对象定义文档的“顶层”。

文档必须至少包含一个下列的顶层成员:

  • data:文档的“主数据”
  • errors错误对象的数组
  • meta元对象,它包含非标准的元信息

成员dataerrors不能同时存在一个文档中。

文档可以包含下列几个顶层成员:

  • jsonapi:描述服务器实现的对象
  • links:与主数据有关的链接对象
  • included:与主数据 和/或 彼此有关的资源对象数组(包含资源)

如果文档没有包含顶层data键(成员),那么include成员则不能出现在文档中。

顶层链接对象可以包含下列成员:

  • self:当前响应文档的链接
  • related:当主数据可以表示成一种资源关联,使用相关资源链接来描述它
  • 主数据的分页链接。

文档中的“主数据”指请求的资源或资源集合。

主数据必须是:

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

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

下面的主数据是单一资源标识对象,它表示了和上面同样的资源:

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

资源的逻辑集合必须表示为一个数组,即使它有一项或为空。

资源对象

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

资源对象必须至少包含以下顶层成员:

  • id
  • type

例外:当资源对象源于客户端或者是用于表示即将要在服务器上创建的新资源时,id成员不是必须的。

此外,资源对象可以包含下列任意的顶层成员:

  • attributes属性对象表示该资源的一些数据
  • relationships关联对象描述该资源与其他JSON API资源的关联
  • links连接对象包含与该资源有关的链接
  • meta元对象包含与资源有关,但不能表示为属性或关联的非标准元信息

下面展示了一篇文章(即类型为“articles”的资源)在文档中是怎么样的:

// ...
{
  "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" }
    }
  }
}
// ...

标识符

每个资源对象必须包含id成员和type成员。同时必须设置idtype成员的值。

在给定的API中,每个资源对象typeid必须表示一个唯一的资源。(URL的集合由一台服务器或者服务器集群控制,这些URL的集合构成了API。)

type成员用来描述拥有共同属性和关联的资源对象

type成员的值必须遵循与成员名称一样的原则。

说明:该规范无法预知所有的情况,所以type的值既可以是单数,也可以是复数。但应该始终使用同样的值。

字段

资源对象的属性attributes和关联relationships统称为字段fields

资源对象resource objects的所有字段必须共用一个命名空间,同时typeid也处在该命名空间中。换句话说,资源对象不能有相同名称的属性或关联,也不能将属性或者关联命名为type或者id

属性

属性的值必须是对象(属性对象)。属性对象(属性)的成员表示它所定义的资源对象resource objects的信息。

属性可以包含任何有效的JSON值。

可以将JSON对象或者数组等复合数据结构作为属性的值。但是构成属性的任何对象都不能含有relationshipslinks成员,因为这些成员被留作将来使用。

尽管外键(例如:author_id)通常与其他信息存储在一起,但这些键不应该出现在属性中。

说明:请参见字段成员命名来了解更多的约束条件。

关联

relationships的值必须是一个对象(关联对象)。关联对象(”关联”)的成员表示从当前资源对象到它所定义的那个资源对象的引用。

关联可以是一对一也可以是一对多

一个关联对象必须至少包含下列成员中的一个:

  • links链接对象至少包含下列成员中的一个:
    • self:关联自身的链接(“关联链接”)。该链接允许客户端直接操纵关联。 例如:通过author的关联URL来移除一个author,会导致presonauthor之间的连接断开,但并不会删除person。 当获取成功后,链接会返回以相关资源为主数据的联动。(参见获取关联。)
    • related相关资源链接
  • data资源联动
  • meta: 与关联有关的不规则的元信息构成的元对象

表示一对多关联的关联对象,还可以像下面描述的那样,在links成员里加上分页pagination

说明:请参见字段成员命名来了解更多的约束条件。

相关资源链接

“相关资源链接”提供了访问关联中的资源对象链接的方法。在访问的时候,相关资源对象会作为响应的主数据返回。

例如,article的’comments’关联可以指定一个链接,当通过GET请求该链接时,返回一个评论集合的资源对象。

如果存在相关资源链接,就必须引用有效的URL,即使关联不与任何目标资源关联。 此外,一个相关资源链接不能因关联的内容的变化而改变。

资源联动

复合文档中的资源联动允许客户端将所有包含的资源对象连在一起,无需通过GET访问链接links中的任何URL。

资源联动必须是下列中的一种

  • 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关联包含了关联本身的一个链接(允许客户端直接更改相关的作者),以及一个可以直接获取资源对象和联动信息的相关资源链接。

资源链接

资源对象中的可选links成员含有与链接相关的资源。

链接对象可以包含一个self链接links,该链接标识了该资源对象所表示的资源。

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

服务器必须响应指定URL的GET请求,并返回以资源为主数据的响应。

资源标识对象

“资源标识对象”用于标识一个唯一的资源。

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

“资源标识对象”也可以包含mate成员,它的值是一个包含非标准元信息的对象。

复合文档

为了减少HTTP的请求数量,服务器可以将相关资源以及所需的主要资源放在同一个响应中返回给客户端。这种响应方式称为“复合文档”。

在复合文档中,所有的资源必须被表示成一个资源对象数组,并放在顶层included成员中。

符合文档需要“全联动”,这意味着每个在文档中的资源必须至少被资源标识对象标识一次。这些资源标识符要么是主数据,要么就是包含资源联动的主资源或者包含资源。

全联动要求唯一可以例外的是,原本包含联动的关系字段通过被稀疏字段集排除在外。

说明:全联动确保被包含的资源是与主数据(可能是资源对象或者资源标识对象)或者彼此相关的。

多包含关系的完整示例文档:

{
  "data": [{
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON API paints my bikeshed!"
    },
    "links": {
      "self": "http://example.com/articles/1"
    },
    "relationships": {
      "author": {
        "links": {
          "self": "http://example.com/articles/1/relationships/author",
          "related": "http://example.com/articles/1/author"
        },
        "data": { "type": "people", "id": "9" }
      },
      "comments": {
        "links": {
          "self": "http://example.com/articles/1/relationships/comments",
          "related": "http://example.com/articles/1/comments"
        },
        "data": [
          { "type": "comments", "id": "5" },
          { "type": "comments", "id": "12" }
        ]
      }
    }
  }],
  "included": [{
    "type": "people",
    "id": "9",
    "attributes": {
      "first-name": "Dan",
      "last-name": "Gebhardt",
      "twitter": "dgeb"
    },
    "links": {
      "self": "http://example.com/people/9"
    }
  }, {
    "type": "comments",
    "id": "5",
    "attributes": {
      "body": "First!"
    },
    "relationships": {
      "author": {
        "data": { "type": "people", "id": "2" }
      }
    },
    "links": {
      "self": "http://example.com/comments/5"
    }
  }, {
    "type": "comments",
    "id": "12",
    "attributes": {
      "body": "I like XML better"
    },
    "relationships": {
      "author": {
        "data": { "type": "people", "id": "9" }
      }
    },
    "links": {
      "self": "http://example.com/comments/12"
    }
  }]
}

复合文档的每个typeid键值对不能表示超过一个资源对象

注:在单个文档中,你会想到将将typeid作为组合键来唯一地索引另一个文档中的资源对象

注:这种方法可以确保每个响应都能返回一个规范的资源对象,即便是在同样资源被多次引用的情况下。

元信息

当需要的时候,meta成员可以用于存放多个非标准的元信息。每个meta成员的值必须是一个对象(“元对象”)。

任何成员都可以放在meta对象中。

例如:

{
  "meta": {
    "copyright": "Copyright 2015 Example Corp.",
    "authors": [
      "Yehuda Katz",
      "Steve Klabnik",
      "Dan Gebhardt",
      "Tyler Kellen"
    ]
  },
  "data": {
    // ...
  }
}

链接

当需要的时候,links成员可以用来表示链接。links成员的值必须是一个对象(“链接对象”)。

链接对象的每个成员都是一个“链接”,链接必须是下面的任一种表示方式:

  • 一个包含链接URL的字符串
  • 一个包含下列成员的对象(链接对象):
    • href:一个包含链接URL的字符串。
    • meta:一个包含关于链接的非标准元信息的元对象。

以下”self”链接仅仅是一个URL:

"links": {
  "self": "http://example.com/posts",
}

以下reltated链接包含一个URL,同时包含相关资源集合的元信息:

"links": {
  "related": {
    "href": "http://example.com/articles/1/comments",
    "meta": {
      "count": 10
    }
  }
}

注:附加的成员是将来指定给links对象和link对象的。可能附加成员的允许值会在以后扩展(如,一个collection链接或许支持一个值数组,然而self链接却不是)。

JSON API对象

JSON API文档可以包含其实现在一个顶层jsonapi成员下的信息。Jsonapi成员的值必须以一个对象(jsonapi对象)的形式出现。Jsonapi对象可以包含一个version对象,它的值是一个表明支持最高高版本JSON API的字符串。此对象也可以包含一个meta成员,它的值是一个包含非标准元信息的meta对象。

{
  "jsonapi": {
    "version": "1.0"
  }
}

如果没有version成员,客户端应假定服务器端实现至少符合的规范版本为1.0。

注:因为JSON API只致力于作添加的改变,版本字符串主要表明一个服务器可能支持的新特性。

成员名

一个JSON API文档中的所有成员名命名必须视客户端和服务器端对大小写敏感,且必须符合以下条件:

  • 成员名必须至少包含一个字符。
  • 成员名必须只能包含以下列出的字符:
  • 成员名必须以如下定义的一个全局允许的字符起始和结束。

为了使一个简单的成员名到URL的映射可用,成员名应该只用非保留字符,URL安全字符指定在RFC 3386文档中。

允许使用的字符

以下全局可用的字符可以使用于一个成员名的任何地方:

  • Unicode 0061到007A,即”a”到“z”
  • Unicode 0041到 005A,即”A“到”Z”
  • Unicode 0030到0039,即“0”到“9”
  • Unicode 0080及之后的字符(非ASCII Unicode字符,不建议、非URL安全字符)

Additionally, the following characters are allowed in member names, except as the first or last character:

  • U+002D HYPHEN-MINUS, “-“
  • U+005F LOW LINE, “_”
  • U+0020 SPACE, “ “ (not recommended, not URL safe)

保留字符

以下字符不能用在成员名中:

  • U+002B 加号, “+” (用于排序)
  • U+002C 逗号, “,” (作为关联路径间的分隔符)
  • U+002E 句号, “.” (作为关联路径内的分隔符)
  • U+005B 左中括号, “[” (用于稀疏字段中)
  • U+005D 右中括号, “]” (用于稀疏字段中)
  • U+0021 感叹号, “!”
  • U+0022 引号, ‘”’
  • U+0023 数字符号(井号), “#”
  • U+0024 美元符, “$”
  • U+0025 百分号, “%”
  • U+0026 与号, “&”
  • U+0027 省略号, “’”
  • U+0028 左括号, “(“
  • U+0029 右括号, “)”
  • U+002A 星号, “*”
  • U+002F 斜杠, “/”
  • U+003A 冒号, “:”
  • U+003B 分号, “;”
  • U+003C 小于号, “<”
  • U+003D 等号, “=”
  • U+003E 大于号, “>”
  • U+003F 问号, “?”
  • U+0040 商用AT符号, “@”
  • U+005C 反斜杠, “"
  • U+005E 抑扬音符号, “^”
  • U+0060 沉音符, “`”
  • U+007B 左波形括号, “{“
  • U+007C 竖线, “
  • U+007D 右波形括号, “}”
  • U+007E 波浪号, “~”
  • U+007F 删除
  • U+0000 到 U+001F (联合控制)

    译者注:以上符号均为英文中使用的符号。

获取数据

数据,包括资源和关联,可以通过发送GET请求到一个端点获取。

响应可以细化为以下描述的可选的特性。

获取资源

服务器端必须支持获取如下提供给每个URL的资源数据:

  • 一个self链接作为顶层”links“对象的一部分
  • 一个self链接作为资源层”links”对象的一部分
  • 一个related链接作为关联层”links”对象的一部分

例如,下列请求获取一个”articles”集合:

GET /articles HTTP/1.1
Accept: application/vnd.api+json

以下请求获取一个“article”:

GET /articles/1 HTTP/1.1
Accept: application/vnd.api+json

而以下请求获取一个”article”的“author”:

GET /articles/1/author HTTP/1.1
Accept: application/vnd.api+json

响应

200 OK

服务器必须回应“200 OK”响应一个成功的请求来获取单个资源或者资源集合。

服务器必须以一个资源对象数组或空数组作为响应文档的主要数据,响应一个成功的请求来获取一个资源集合。

例如,一个对“articles”集合的GET请求可以如此响应返回:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "links": {
    "self": "http://example.com/articles"
  },
  "data": [{
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON API paints my bikeshed!"
    }
  }, {
    "type": "articles",
    "id": "2",
    "attributes": {
      "title": "Rails is Omakase"
    }
  }]
}

表明为一个空集合的相似响应应当是:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "links": {
    "self": "http://example.com/articles"
  },
  "data": []
}

服务器以一个资源对象或null作为响应文档的主要数据,响应一个成功的请求来获取单个资源。

当一个请求的URL对应一个资源,而这个资源目前没有时,null只是一个合理的响应

注:例如,考虑请求到一个到相关资源的链接。当关联为空时,这个请求将回应null(这样对应的链接是没有资源的),但是单独相关的资源的resource对象则相反。

例如,一个对单个“article”的GET请求可以如下返回:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "links": {
    "self": "http://example.com/articles/1"
  },
  "data": {
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "JSON API paints my bikeshed!"
    },
    "relationships": {
      "author": {
        "links": {
          "related": "http://example.com/articles/1/author"
        }
      }
    }
  }
}

如果以上“article”的“author”丢失了,那么对那个相关资源的GET请求会如下返回:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "links": {
    "self": "http://example.com/articles/1/author"
  },
  "data": null
}
404 Not Found

当处理一个请求来获取不存在的单个资源时,除了保证一个以null为主要数据 200 OK响应外,服务器还必须以404 Not found响应,

其他响应

服务器可以以其他HTTP状态码响应。

服务器可以响应包含错误细节的错误。

服务器必须准备响应,且客户端必须根据HTTP语义解释响应。

获取关联

服务器必须支持获取关联数据,包含self链接作为一个关联的links对象的一部分。

例如,以下获取对一个“article”的评论数据的请求:

GET /articles/1/relationships/comments HTTP/1.1
Accept: application/vnd.api+json

以下请求获取关于一个”article”的”author”的数据:

GET /articles/1/relationships/author HTTP/1.1
Accept: application/vnd.api+json

响应

200 OK

服务器端必须回应以一个200 OK响应一个来获取关联的成功请求。

响应文档中的主要数据必须符合资源链接的合理值,对于关联对象的描述见上。

顶层链接对象可以包含selfrelated链接,对于关联对象的描述见上。

例如,一个对来自单向关联链接的URL的GET请求可以返回:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "links": {
    "self": "/articles/1/relationships/author",
    "related": "/articles/1/author"
  },
  "data": {
    "type": "people",
    "id": "12"
  }
}

如果以上关联是空的,那么到相同URL的一个GET请求将如下返回:

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "links": {
    "self": "/articles/1/relationships/author",
    "related": "/articles/1/author"
  },
  "data": null
}

从对多关联链接GET请求到URL发送可以返回 ︰

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "links": {
    "self": "/articles/1/relationships/tags",
    "related": "/articles/1/tags"
  },
  "data": [
    { "type": "tags", "id": "2" },
    { "type": "tags", "id": "3" }
  ]
}

如果以上的关联为空,则对同一个URL 发送GET请求将返回︰

HTTP/1.1 200 OK
Content-Type: application/vnd.api+json

{
  "links": {
    "self": "/articles/1/relationships/tags",
    "related": "/articles/1/tags"
  },
  "data": []
}
404 Not Found

服务器必须返回404 Not Found来处理获取不存在关联链接URL的请求。

注︰这可以发生在关联的父资源不存在时。例如,当/articles/1不存在,请求/articles/1/relationships/tags时就会返回404 Not Found.

如果关联链接URL存在,但关联是空的,那么必须返回200 OK ,如上文所述。

其他响应

服务器可以用其他 HTTP 状态代码作为响应。

服务器可以使用错误响应包含错误的详细信息。

服务器必须准备响应,且客户端必须根据HTTP语义解释响应。

相关资源的包含

端点可以返回默认情况下与主数据相联的资源。

端点可能还支持included请求参数,以允许客户端应该返回自定义的相关资源。

如果端点不支持included参数,那么任何包含它的请求,服务器必须响应400 Bad Request

如果端点支持included参数并且由客户端提供它,服务器在[复合文档]中included节中不能包含未请求的[资源对象].

include参数的值必须是英文逗号分隔 (U+002C + 逗号,”,”) 的关联路径列表。关联路径是圆点分隔 (U + 002E 句号,”.”) 的关联名称列表。

如果服务器无法识别关联路径或不支持从一个路径包含资源,它必须做出400 Bad Request响应。

注︰例如,关联路径可以是comments.author,其中commentsarticles资源对象下列出的关联, authorcomments资源对象下列出的关联。

例如,“comments”可以请求一篇“article”︰

GET /articles/1?include=comments HTTP/1.1
Accept: application/vnd.api+json

为了请求资源可以关联到其他资源,可以用圆点分隔的路径指定每个关系名称︰

GET /articles/1?include=comments.author HTTP/1.1
Accept: application/vnd.api+json

注︰由于复合文档需要充分联动 (除了当关联联动不被由稀疏的字段集所包含),多部分路径的中间资源必须伴随着叶节点返回。例如, comments.author请求的响应应该包括comments,以及author,对于每个comments都一样.

注︰服务器可以选择公开嵌套很深的关联如comments.author作为一个直接关联comment-authors的别名。这将允许客户端请求/articles/1?include=comment-authors而不是/articles/1?include=comments.author。通过抽象与别名办税伴随嵌套的关联,服务器仍能提供在复合文档中的充分联动,且不包含可能有害的中间资源。

多个相关的资源可以以逗号分隔的列表作为请求︰

GET /articles/1?include=author,comments.author HTTP/1.1
Accept: application/vnd.api+json

此外,相关的资源可以从关联端点请求︰

GET /articles/1/relationships/comments?include=comments.author HTTP/1.1
Accept: application/vnd.api+json

在这种情况下,主数据将代表关联到文章的评论的资源标识符对象集合,而完整的评论和评论作者将作为包含数据返回。

注︰本条适用于任何以主数据作为响应,而不考虑请求类型的端点。例如,服务器可以支持包含的相关资源伴随一个POST请求去创建资源或关联。

稀疏字段集

客户端可以请求一个端点返回,只能在响应中每种类型的基础上指定fields中包含特定fields[TYPE]参数。

fields的值必须是用逗号分隔(U +002 C + 逗号,”,”)的列表 ,该列表指的是要返回字段的名称列表。

如果客户端请求一组限定资源类型的fields,端点的响应不能包含附加fields在该类型的资源对象中。

GET /articles?include=author&fields[articles]=title,body&fields[people]=name HTTP/1.1
Accept: application/vnd.api+json

注︰上面的示例中的 URI 显示未编码的[]字符只是为了提高可读性。在实践中,这些字符必须是百分号编码的,将根据在 RFC 3986的要求.

注︰本条适用于任何以资源作为主体或包含数据,而不是考虑请求类型的端点。例如,服务器可以支持稀疏字段集伴随着一个POST请求去创建资源。

排序

服务器可以支持对请求根据一个或多个标准(”排序字段”)对资源集合进行排序。

注︰尽管推荐,但是排序字段对于资源属性和关联的名称来说不是必需的。

注︰建议用圆点分隔 (U + 002E 句号,”.”) 排序字段来请求基于关联属性的排序。例如, author.name排序字段可以用于对请求的主数据进行根据author关系的name属性的排序。

端点可以支持通过包含sort的查询参数请求进行主要数据的排序。sort必须代表排序字段的值。

GET /people?sort=age HTTP/1.1
Accept: application/vnd.api+json

端点可以支持多个排序字段,通过允许逗号分隔 (U+002 C + 逗号, “,”) 排序字段。排序字段应该应用于指定排序。

GET /people?sort=age,name HTTP/1.1
Accept: application/vnd.api+json

每个排序字段的排序顺序必须升序,除非它以减号作为前缀 (U + 002D 连字符-负号,”-“),在这种情况下它必须降序。

GET /articles?sort=-created,title HTTP/1.1
Accept: application/vnd.api+json

上面的例子应该先返回最新的”articles”。在同一日期上创建的任何”articles”将会按其”title”按字母顺序升序排序。

如果服务器不支持指定查询参数sort,它必须返回400 Bad Request响应。

如果排序是服务器所支持的并且查询参数sort通过客户端请求,服务器必须返回根据指定条件排序的顶层元素data数组响应。如果请求不指定sort参数,服务器可以应用默认排序规则对顶级data进行排序。

注︰本条适用于任何以资源集合作为主要数据,而不考虑请求类型的响应。

分页

为了让整个集合的一个子集 (”页面”) 可用,服务器可以选择限制响应中返回的资源数量。

服务器可以提供链接来遍历一个分页的数据集 (”分页链接”)。

分页链接必须出现在对应于一个集合的链接对象中。为了对主要数据进行分页,在顶级links对象中提供分页链接。要分页在返回的复合文档中所包含的集合,提供分页链接中对应的链接对象。

分页链接对象必须用以下关键字︰

  • first︰ 数据的第一页
  • last︰ 数据的最后一页
  • prev︰ 数据的前一页
  • next︰ 数据的下一个页面

关键词必须省略或者为空值,以表示特定的链接是不可用的。

正如表示在分页链接的命名中那样,顺序的概念必须与JSON API排序规则保持一致。

page查询参数是为分页保留的。服务器和客户端应该将此关键词用于分页操作。

注︰JSON API与服务器所使用的分页策略无关。有效的分页策略包括 (但不是限于)︰基于页面的、基于偏移量,和基于指针的。page查询参数可以用作任何这些策略的基础。例如,基于页面的策略可能会使用查询参数,如page[number]page[size],偏移量为基础的策略可能使用page[offset]page[limit],而基于游标的策略可能使用page[cursor].

注︰上面的示例查询参数使用未编码的[]字符只是为了提高可读性。在实践中,这些字符必须是%编码,将根据在RFC 3986的要求。

注︰本条适用于任何以资源集合作为主要数据,而不考虑请求类型的响应。

过滤

filter查询参数为筛选数据保留。服务器和客户端应该使用这个关键词进行过滤操作。

注︰JSON API与服务器所支持的策略无关。filter查询参数可以作为任意数量的过滤策略的基础。

创建、更新和删除资源

服务器可以允许创建给定类型的资源。它也可以允许对现有的资源进行修改或删除。

请求必须是完全成功或失败(在单次”处理”中)。不允许部分更新。

注︰type被要求贯穿在整个JSON API请求和响应的每一个资源对象中。某些情况下,如正在POST到一个代表易购数据的端点时,无法从断点推断类型时,当它需要挑选和选择时会困惑,它会难以记住何时需要,何时不需要。因此,需要type提高一致性,减少迷惑性。

创建资源

通过发送POST请求到资源集合的URL,可以创建一个资源。这个请求必须包含一个单独的资源对象作为主要数据。这个资源对象必须包含至少一个type成员。

例如,以下的请求可能会创建一张新”photo”︰

POST /photos HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": {
    "type": "photos",
    "attributes": {
      "title": "Ember Hamster",
      "src": "http://example.com/images/productivity.png"
    },
    "relationships": {
      "photographer": {
        "data": { "type": "people", "id": "9" }
      }
    }
  }
}

如果资源对象中的relationships成员被提供了一种关联,那么它的值必须是一个关联对象与一个data成员。此关键字的值代表新的资源是有关联的。

客户端生成的ID

服务器可以接受客户端生成的ID伴随在请求中去创建资源。ID必须指定id关键词,它的值必须是一个通用唯一标识符。客户端应该使用正确生成和格式化的 UUID 如RFC 4122 [RFC4122]中所述.

注︰在一些用例,如从其他源导入数据中有可能使用其他代替UUID,但仍然保证是全局唯一的。请不要使用 UUID 之外的任何内容,除非你100%的确定你正在使用的策略确实生成全局唯一标识符。

例如︰

POST /photos HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": {
    "type": "photos",
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "attributes": {
      "title": "Ember Hamster",
      "src": "http://example.com/images/productivity.png"
    }
  }
}

服务器必须返回403 Forbidden以响应不支持使用客户端生成的 ID请求创建资源。

响应

201 Created

如果一个POST请求不包含一个客户端生成的ID并且所请求的资源已成功创建过的,服务器必须返回一个201 Created状态代码。

响应应该包含确定新创建资源位置的Location标头。

响应必须还包含创建主要资源的文档。

如果返回响应的资源对象在其links成员中包含self关键词,并且提供Location标头,self成员的值必须Location标头的值相一致。

HTTP/1.1 201 Created
Location: http://example.com/photos/550e8400-e29b-41d4-a716-446655440000
Content-Type: application/vnd.api+json

{
  "data": {
    "type": "photos",
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "attributes": {
      "title": "Ember Hamster",
      "src": "http://example.com/images/productivity.png"
    },
    "links": {
      "self": "http://example.com/photos/550e8400-e29b-41d4-a716-446655440000"
    }
  }
}
202 Accepted

如果要创建资源的请求已被接受处理,但处理尚未完成的时候,服务器必须返回202 Accepted状态代码。

204 No Content

如果POST请求包括一个客户端生成的 ID 并且所请求的资源已成功创建,服务器必须返回201 Created状态代码和响应文档 (如上文所述) 或204 No Content状态代码不响应文档。

注︰如果收到204响应,客户端应该认为发送请求的资源对象已经被服务器所接受,就好像服务器已经在201响应中返回了。

403 Forbidden

服务器可以对不支持创建资源的请求来响应403 Forbidden

409 Conflict

服务器必须返回409 Conflict来处理通过一个已经存在的客户端生成ID 来发送POST请求创建资源的情况。

服务器必须返回409 Conflict处理POST请求资源对象的type不是构成该端点所表示的集合类型的情况。

服务器应该包含错误详细信息并提供足够的信息来识别冲突的来源。

其他响应

服务器可以用其他 HTTP 状态代码作为响应。 服务器可以使用包含错误的详细信息的错误响应。 服务器必须准备响应,且客户端必须根据HTTP语义解释响应。

更新资源

可以通过发送PATCH请求到代表资源的URL更新一个资源。

资源URL可以通过资源对象中的self链接获得。或者,当GET请求中返回单独的资源对象作为主数据时,相同URL请求可以用于更新。

PATCH请求必须包含单一的资源对象作为主要数据。资源对象必须包含typeid的成员。

例如:

PATCH /articles/1 HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": {
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "To TDD or Not"
    }
  }
}

更新资源属性

资源的任何或所有的attributes可以包含在PATCH请求的资源对象中。

如果请求不包含资源的所有attributes,服务器必须解释所缺少的attributes,就好像它们已经被包含,附带其当前值。服务器不能将null解释为缺少属性的值。

例如,以下PATCH请求被解释为一个只更新”article”的titletext属性的请求︰

PATCH /articles/1 HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": {
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "To TDD or Not",
      "text": "TLDR; It's complicated... but check your test coverage regardless."
    }
  }
}

更新资源关联

资源的任何或所有relationships可以包含在PATCH请求中的资源对象中。

如果请求没有包含资源的所有关联,服务器必须解释缺失关联与其当前值,就好像包含了一样。服务器不能把它们解释为空或空值。

如果资源对象在PATCH请求中为关联成员提供了关联,它的值必须是一个数据成员的关联对象。该关联的值将被替换为该成员所指定的值。

例如,以下的PATCH请求将更新”article”的author关联:

PATCH /articles/1 HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": {
    "type": "articles",
    "id": "1",
    "relationships": {
      "author": {
        "data": { "type": "people", "id": "1" }
      }
    }
  }
}

同样,下面的PATCH请求执行一个”article”的tags的完全替换:

PATCH /articles/1 HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": {
    "type": "articles",
    "id": "1",
    "relationships": {
      "tags": {
        "data": [
          { "type": "tags", "id": "2" },
          { "type": "tags", "id": "3" }
        ]
      }
    }
  }
}

服务器可以拒绝执行完全的一到多关联的替换。在这种情况下,服务器必须拒绝整个更新,并返回一个403 Forbidden响应信号。

注:因为完全替换可能是一个非常危险的操作,服务器可以选择禁用它。例如,如果未提供客户端相关对象的完整列表,则服务器可以拒绝完全替换,而且不会允许删除客户端没有的记录。

响应

202 Accepted

如果更新请求已被接受处理,但是服务器响应期间的处理还没有结束,服务器必须返回一个202 Accepted状态码。

200 OK

如果服务器接受了更新,但也(除按请求所指定的方式)对资源做了修改(例如,更新updated-at属性或计算sha值),它必须返回一个200 OK响应。响应文档必须包括已更新资源实例,就好像向请求的URL发出了GET请求。

如果更新成功,服务器必须返回一个200 OK的状态码,保持客户端的当前属性为最新,服务器只响应顶层的元meta数据。这种情况下,服务器不能包含已更新资源的实例。

204 No Content

如果更新成功且服务器没有更新除提供更新之外的任何属性,服务器必须返回200 OK状态码和响应文档(如上所述)或 没有响应文档的204 No Content状态码。

403 Forbidden

服务器必须返回403 Forbidden来响应一个不支持更新资源或关联的请求。

404 Not Found

当处理修改不存在的资源请求时,服务器必须返回404 Not Found

当处理引用不存在的相关资源请求时,服务器必须返回404 Not Found

409 Conflict

当处理一个更新资源的PATCH请求时,如果该更新会违反其他服务器的强制约束(如唯一性约束以外的属性标识)规则时,服务器可以返回409 Conflict

在处理一个PATCH请求时,资源对象的typeid和服务器的端点数据不匹配, 服务器必须返回409 Conflict

服务器应该包含错误详细信息并提供足够的信息来确定冲突的根源。

其他响应

服务器可以响应其他HTTP状态码。

服务器可以包含错误的详细信息。

服务器必须准备响应,客户端必须根据HTTP语义解释这些错误信息。

更新关联

尽管关联可随资源被修改(如上所述),但是JSON API还支持独立于关联链接URL的关联更新。

注:关联的更新不暴露底层服务器语义,如洋钥匙。此外,关联可以被更新,而不影响相关资源。例如,如果一篇文章有许多作者,这可以删除其中一个作者,而不删除作者人其本身。相似地,如果一篇文章有许多标签,可以添加或删除标签。在服务器的端罩下,这些例子中的第一个可以用一个洋钥匙来实现 ,第二个可以用一个连接表来实现,但JSON API协议在这两种情况下是相同的 。

注:如果关联已被删除(作为垃圾收集措施),服务器可以选择删除底层资源。

更新对一关联

服务器必须响应一个来自多关联链接的网址的PATCH请求,如下面所描述的。

PATCH请求必须包含一个顶层成员命名的data,包含:

  • 一个与新相关资源相对应的[资源标识符对象]。
  • null,以消除关联。

例如,下面的请求更新一个”article”的”author”:

PATCH /articles/1/relationships/author HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": { "type": "people", "id": "12" }
}

下面的请求将清除同一个“article”的”author”:

PATCH /articles/1/relationships/author HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": null
}

如果关联更新成功,则服务器必须返回一个表示成功的响应.

更新多个关联

服务器必须响应PATCHPOSTDELETE请求至一个URL,它来自到多关联链接,如下所述.

对于所有请求类型,主体必须包含一个data成员,其值是空数组或资源标识符对象数组。

如果客户端向一个到多关联链接的URL发出PATCH请求,则服务器必须完全替换关联中的每一个成员,并且,如果无法找到或访问某些资源,则服务器返回一个适当的错误响应,或者如果服务器不允许完全替换,则返回一个403 Forbidden响应。

例如,下列请求替换了一”article”的每一个“tag”:

PATCH /articles/1/relationships/tags HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": [
    { "type": "tags", "id": "2" },
    { "type": "tags", "id": "3" }
  ]
}

以下要求为一个”article”清楚每一个”tag”:

PATCH /articles/1/relationships/tags HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": []
}

如果客户端向一个关联链接的URL发出POST请求,服务器必须将不存在的指定成员添加到关联中。如果一个给定的typeid已在关联中,则服务器不能重复添加。

注:这符合使用外键多关联的语义数据库,为了避免重复冗余,基于文档的存储在添加前应检查多关联。

如果所有的指定资源都可以添加到关联,或则其已经存在于关联中,则服务器必须返回的表示成功的响应。

注:如果服务器的状态与请求的状态相匹配,则确保了一个请求是成功的, 并有助于避免多个客户端对关联的相同更改引起的无意义的竞争状况。

以下例子中,对ID123的”comments”添加到”article”的”comments”列表中的ID为1

POST /articles/1/relationships/comments HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": [
    { "type": "comments", "id": "123" }
  ]
}

如果客户端向一个关联链接中的URL发起DELETE请求,服务器必须从关联中删除指定的成员,或返回 403 Forbidden响应。如果所有的指定资源都被移除,或者已经在关联中丢失了,服务器必须返回一个表示成功的响应。

注:如上所述的POST请求,这种方法有助于避免因多个客户端之间做出的相同更改无意义竞争状况。

在POST请求中关联成员以同样的方式指定。

以下例子中,在ID为1的”article”中,”comments”列表删除了ID为1213的”comments”:

DELETE /articles/1/relationships/comments HTTP/1.1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "data": [
    { "type": "comments", "id": "12" },
    { "type": "comments", "id": "13" }
  ]
}

注:RFC 7231指定删除请求可以包括本体,但服务器可以拒绝该请求,这个规则定义了一个服务器的语义,我们为JSON API 定义了这种语义。

响应

202 Accepted

如果一个关联更新请求已被接受处理,但是服务器响应处理还没有完成,服务器必须返回一个202 Accepted的状态码。

204 No Content

如果更新成功并且请求中的资源和结果匹配,服务器必须返回一个204 No Content 状态码。

注:当这种关联已经存在时,这是对发送一个到多关联链接的URL的POST请求的合理响应,当这种关联不存在时,对发送一个到多关联链接的URL的DELET请求的合理响应。

200 OK

如果服务器接受更新,但也(除按请求所指明的方式)对资源做了更改,它必须返回一个200 OK 的响应。响应文档必须包含已更新关联的实例表示。

如果更新成功,服务器必须返回200 OK状态码,客户端当前数据保持最新,服务器只响应顶层的meta数据。在这种情况下,服务器不能包含已更新关联的实例表示。

403 Forbidden

对于用不支持的请求来更新关联时,服务器必须返回403 Forbidden响应。

其他响应

服务器可以响应其他HTTP状态码。

服务器可以包括错误资料与错误响应。

服务器必须做好响应准备,客户端必须依据HTTP语义解释响应。

删除资源

通过对资源的URL发出DELETE请求,可以 删除 单个资源:

DELETE /photos/1 HTTP/1.1
Accept: application/vnd.api+json

响应

202 Accepted

如果接受处理一个删除请求,但是服务器响应处理还没有完成,则服务器必须返回一个202 Accepted的状态码。

204 No Content

如果删除请求处理成功,且没有内容返回,那么服务器必须返回一个204 No Content状态码。

200 OK

如果删除请求成功,且服务器只回应以顶层meta数据,那么服务器必须返回一个200 OK状态码。

其他响应

服务器可以响应其他HTTP状态码。

服务器可以包括错误信息的错误响应。

服务器必须做好响应准备,客户端必须依据HTTP语义解释响应。

查询参数

实现特定的查询参数必须遵循相同的约束,附加要求是作为成员姓名字段必须至少包含一个非a-z字母字符(U+0061到U+007a)。可以 用 U+002D 连字号-负号”-“, U+005F 下划线”_“,或者使用大写字母(如camelCasing)。

如果服务器处理遇到一个不遵循以上命名规则的查询参数,而服务器不知道如何按此规范处理该查询参数,则服务器必须返回400 Bad Request响应。

注:这是保护JSONAPI对标准查询参数处理与现有实现冲突而增加的功能。

错误

错误处理

服务器可以选择在遇到问题时尽快停止处理进程,也可以选择继续处理并遇到更多的问题。 例如,服务器可能会处理多个属性,然后会将多个验证错误放在同一个响应中返回。

当服务器遇到一个请求的多个问题时,响应应该是最普遍适用的HTTP错误代码。例如,400 Bad Request可以适用于4xx错误,或者500 Internal Server Error可以适用于5xx错误。

错误对象

错误对象在执行操作时提供了有关问题的附加信息。在JSON API文档的顶层中,错误对象必须作为一个错误键数组返回。

一个错误对象可以有以下成员:

  • id: 特定问题的唯一标示符。
  • links:一个包含下列成员的链接对象
    • about:导致这个特殊问题发生的进一步细节的一个链接
  • status:适用于这个问题的HTTP状态码,使用字符串表示。
  • code:应用程序特定的错误代码,表示为字符串值。
  • title:简短的,可读性高的问题总结,除了国际化本地化处理之外,不同场景下,相同的问题,值是不应该变动的。
  • detail:针对该问题的高可读性解释,就像Title,这个字段的值可以被本地化。
  • source:一个包含错误源引用的对象,任选地包含下列任何成员:
    • pointer:一个指向请求文档中的关联实体的JSON指针[RFC6901](例如”/data”是对应于一个主要数据对象,或”/data/attributes/title” 是对应于一个特定的属性)。
    • parameter:一个是由URL查询参数引起错误的字符串。
  • meta:一个包含非标准元信息的元对象