文档结构
这一章节描述JSON API文档结构,通过媒体类型application/vnd.api+json
标示。JSON API文档使用javascript 对象(JSON)[RFC4627]定义。
尽管同种媒体类型用以请求和响应文档,但某些特性只适用于其中一种。差异在下面呈现。
Top Level
JSON 对象必须位于每个JSON API文档的根级。这个对象定义文档的“top level”。
文档的top level必须包含请求资源或者请求资源集合的实例 (即主要资源)。
主要资源应该以资源类型或者通用键"data"
索引.
"meta"
: 资源的元信息,比如分页."links"
: 扩展资源关联URLs的URL模板."linked"
: 资源对象集合,按照类型分组,链接到主要资源或彼此(即链接资源)
资源表示
这一章节描述JSON API文档如何表示资源。适用于主要资源和链接资源。
个体资源表示
个体资源使用单一“资源对象”(如下描述)或者包含资源ID(如下描述)的字符串表示。
The following post is represented as a resource object: 下面的post表示一个资源对象:
{
"posts": {
"id": "1",
// ... attributes of this post
}
}
这个post用ID简单地表示:
{
"posts": "1"
}
资源集合表示
任意数量资源的集合应该使用资源对象数组,或者IDs数组,或者一个简单的”集合对象“表示。
下面这个post使用资源对象数组表示:
{
"posts": [{
"id": "1"
// ... attributes of this post
}, {
"id": "2"
// ... attributes of this post
}]
}
这个posts使用IDs数组表示:
{
"posts": ["1", "2"]
}
这些comments使用单一集合对象表示:
{
"comments": {
"href": "http://example.com/comments/5,12,17,20",
"ids": [ "5", "12", "17", "20" ],
"type": "comments"
}
}
多资源对象
多个资源对象有相同的内部结构,不管他们表示主要资源还是链接资源。
下面是一个可能出现在文档中的post(即”posts"类型的一个资源):
{
"posts": {
"id": "1",
"title": "Rails is Omakase"
}
}
在上面这个例子中,post的资源对象比较简单:
//...
{
"id": "1",
"title": "Rails is Omakase"
}
//...
这一章节专注于资源对象,在完整JSON API文档上下文环境之外。
资源属性
资源对象有四个保留字:
"id"
"type"
"href"
"links"
资源对象中的其它键表示一个“属性”。一个属性值可以是任何JSON值。
资源 IDs
Each resource object SHOULD contain a unique identifier, or ID, when
available. IDs MAY be assigned by the server or by the client, as described
below, and SHOULD be unique for a resource when scoped by its type. An ID
SHOULD be represented by an "id"
key and its value MUST be a string
which SHOULD only contain alphanumeric characters, dashes and underscores.
每一个资源对象应该有一个唯一标示符,或者ID。如下所示,IDs可由服务器或者客户端指定,and SHOULD be unique for a resource when scoped by its type. ID应该使用 "id"
键表示,值必须是字符串,且只包含字母,数字,连字符和下划线。
URL 模板可以使用IDs来获取关联资源,如下所示。
在特殊场景下,客户端与服务器之间的唯一标识符信息非必要,JSON API允许缺省IDs。
资源类型
每个资源对象的类型通常由它所在的上下文环境决定。如上面讨论,资源对象在文档中通过类型索引。
每一个资源对象可能包含 "type"
键来显示指定类型。
当资源的类型在文档中未声明时,"type"
键不可缺省。
资源 URLs
每一个资源的URL可能使用"href"
键声明。资源URLs应该由服务器指定,因此通常包含在响应文档中。
//...
[{
"id": "1",
"href": "http://example.com/comments/1",
"body": "Mmmmmakase"
}, {
"id": "2",
"href": "http://example.com/comments/2",
"body": "I prefer unagi"
}]
//...
服务器对特定URLGET
请求,响应内容必须包含资源。
通常在响应文档的根层级声明URL 模板会更高效,而不是在每一个资源对象内声明独立的URLs。
资源关联
"links"
键的值是一个表示链接资源的JSON对象,通过关联名索引。
举例来说,下面的post与一个author
和一个comments
集合相关联:
//...
{
"id": "1",
"title": "Rails is Omakase",
"links": {
"author": "9",
"comments": [ "5", "12", "17", "20" ]
}
}
//...
单对象关联
单对象关联必须使用上面所述单资源形式的一种来表示。
举例来说,下面的post与一个author相关联,通过ID标示:
//...
{
"id": "1",
"title": "Rails is Omakase",
"links": {
"author": "17"
}
}
//...
下面是一个示例,链接的author用一个资源对象表示:
//...
{
"id": "1",
"title": "Rails is Omakase",
"links": {
"author": {
"href": "http://example.com/people/17",
"id": "17",
"type": "people"
}
}
}
//...
空白的单对象关联应该用null
值表示。举例来说,下面的post没有关联author:
//...
{
"id": "1",
"title": "Rails is Omakase",
"links": {
"author": null
}
}
//...
多对象关联
多对象关联必须使用上述资源集合形式的一种来表示。
举例来说,下面的post与多个comments关联,通过IDs标示:
//...
{
"id": "1",
"title": "Rails is Omakase",
"links": {
"comments": [ "5", "12", "17", "20" ]
}
}
//...
这是一个使用集合对象链接的comments数组:
//...
{
"id": "1",
"title": "Rails is Omakase",
"links": {
"comments": {
"href": "http://example.com/comments/5,12,17,20",
"ids": [ "5", "12", "17", "20" ],
"type": "comments"
}
}
}
//...
空白的多对象关联应该使用空数组表示。举例来说,下面的post没有comments:
//...
{
"id": "1",
"title": "Rails is Omakase",
"links": {
"comments": []
}
}
//...
集合对象
“集合对象”包含一个或多个元素:
"ids"
- 关联资源的IDs数组。"type"
- 资源类型"href"
- 关联资源的URL(适用于响应文档)。
提供包含href
属性集合对象的服务器,必须响应特定URL GET
请求,响应内容包含资源对象集合的关联资源。
URL模板
顶层的 "links"
对象可用来声明URL模板,从而依据资源对象类型获取最终URLs。
举例说明:
{
"links": {
"posts.comments": "http://example.com/comments?posts={posts.id}"
},
"posts": [{
"id": "1",
"title": "Rails is Omakase"
}, {
"id": "2",
"title": "The Parley Letter"
}]
}
在这个示例中,请求http://example.com/comments?posts=1
将会得到"Rails is Omakase"
的comments,请求http://example.com/comments?posts=2
将会得到 "The Parley Letter"
的comments.
下面是另外一个示例:
{
"links": {
"posts.comments": "http://example.com/comments/{posts.comments}"
},
"posts": [{
"id": "1",
"title": "Rails is Omakase",
"links": {
"comments": [ "1", "2", "3", "4" ]
}
}]
}
在这个示例中,处理每个post"links"
区块内的特定数组,以扩展posts.comments
变量。URI模板规范 [RFC6570]声明默认处理方式,使用%编码(即encodeURIComponent()
javascript原生方法)编码每一个元素,然后用逗号连接。在这个示例中,请求http://example.com/comments/1,2,3,4
,将会获取一个comments
列表。
顶层 "links"
对象具有以下行为:
- 每个键使用点分隔路径,指向重复的关联。路径以特定资源类型名开头,遍历相关的资源。举例来 说,
"posts.comments"
指向每个"posts"
对象的"comments"
关联. - 每个键的值作为URL模板处理。
- 每个path指向的资源,就像是使用实际指定的非URL值扩展URL模板形成的关联。
这是另外一个使用单对象关联的示例:
{
"links": {
"posts.author": "http://example.com/people/{posts.author}"
},
"posts": [{
"id": "1",
"title": "Rails is Omakase",
"links": {
"author": "12"
}
}, {
"id": "2",
"title": "The Parley Letter",
"links": {
"author": "12"
}
}, {
"id": "3",
"title": "Dependency Injection is Not a Virtue",
"links": {
"author": "12"
}
}]
}
这个实例中,三个posts指向author的URL都为http://example.com/people/12
.
顶层URL模板允许指定关联作为IDs,但是不要求客户端硬编码来获取URLs的信息.
注意:为防止冲突,单独资源对象的links
对象优先级高于顶层的links
对象。
复合文档
为减少HTTP请求,响应需要返回所请求的主要资源,同时可以选择性的包含链接资源。这样的响应称作“复合文档”。
在复合文档中,链接资源必须作为资源对象,包含在文档顶层"linked"
对象中,依据类型,组合到不同数组中。
每个关联的类型,可以在资源层级,或顶层"links"
对象层级,使用"type"
键指定。能够辅助客户端查询链接资源对象。
{
"links": {
"posts.author": {
"href": "http://example.com/people/{posts.author}",
"type": "people"
},
"posts.comments": {
"href": "http://example.com/comments/{posts.comments}",
"type": "comments"
}
},
"posts": [{
"id": "1",
"title": "Rails is Omakase",
"links": {
"author": "9",
"comments": [ "1", "2", "3" ]
}}, {
"id": "2",
"title": "The Parley Letter",
"links": {
"author": "9",
"comments": [ "4", "5" ]
}}, {
"id": "1",
"title": "Dependency Injection is Not a Virtue",
"links": {
"author": "9",
"comments": [ "6" ]
}
}],
"linked": {
"people": [{
"id": "9",
"name": "@d2h"
}],
"comments": [{
"id": "1",
"body": "Mmmmmakase"
}, {
"id": "2",
"body": "I prefer unagi"
}, {
"id": "3",
"body": "What's Omakase?"
}, {
"id": "4",
"body": "Parley is a discussion, especially one between enemies"
}, {
"id": "5",
"body": "The parsley letter"
}, {
"id": "6",
"body": "Dependency Injection is Not a Vice"
}]
}
}
这种处理方式,保证随每个响应返回每个文档的单例,即使当相同的文档被多次引用时(这个实例中三个posts的author)。沿着这种方式,如果主要文档链接到另外的主要或链接文档,在"linked"
对象中也不应该重复。