返回首页 用 JSON 构建 API 的标准指南
FAQ

文档结构

这一章节描述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"对象中也不应该重复。

上一篇: 介绍 下一篇: URLs