{JSON:API} 入门教程
JSON API 起初是由 Yehuda Katz 于2013年3月起草并于2015年3月达到稳定版本,它能让你的 API 调用充满效率。你可以按你所需接收数据,随着需求的改变添加、移除属性或关系。这最大限度减少了数据量和编写API调用接口的周期。
{json:api}
JSON API 文件工作原理跟其他任何 API 格式一样,你发送一个请求到一个终端然后接收你的文件。JSON API 文件定义了资源是如何组织的。这种组织形式有助于标准化你调用API的方式。
例如,当你通过一个简单的 GET
请求调用 articles
资源。
GET /articles HTTP/1.1
Accept: application/vnd.api+json
你接收到的响应看起来大概是这样子的:
// ...
{
"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 relationship 包含了自身关系 self 的链接和有关关联的一些基本信息。使用文件里面的链接,你可以从关联资源检索信息。
但这些仅仅谈及表面的功能。还有一些功能让JSON API使用起来非常友好。
复合文件
为了减少 HTTP 请求数,服务器 可能 允许请求主资源包含关联资源的响应。这种响应就叫做 「复合文件」
复合文件是包含了含有关联关系的数据。例如,当请求一篇如先前例子所示的文章,它可能包含作者的数据,所以你不需要第二次调用来接收文章作者的信息。
从它的一些用处来看,这是非常棒的。一次调用就能获取你想要的资源的全部数据,这是闻所未闻的,除非指定终端是已经编码好的。对于服务端处理来说,缓存和验证一次这样的请求是很容易的。
让我们来看一下这个例子,它返回一个文件的集合。
{
"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"
}
}]
}
如果你查看 included
属性,你会看到文章的所有关联资源。每一个内含的文件中都有一个定义资源返回哪种类型的 type
属性以及一个终端获取文件所对应的链接。
在 article
中,仅通过 id
和 type
来指向 author
关联以及从 included
标签来加载相关的 people
,这看起来有点怪怪的。但是,想象一下,当有很多文章指向同一个 author
,文件仅需要在 included
数据中引用 people
一次。相当有效率!
内联资源
在上面的示例中,服务器在响应中包括所有关系,但是默认情况下您可能不希望这样,因为这会使响应有点膨胀。为此,规范提供了一种指定响应中应包含哪些关系的方法。
例如,如果您只需要 author
包含的关系,则可以使用 include
请求参数调用。这将告诉服务器仅发送与响应的指定关系。
GET /articles/1?include=author HTTP/1.1
Accept: application/vnd.api+json
如果您需要多个关系,可以使用逗号 (,
) 。
当定义包含时,您可以更进一步并包含嵌套关系。例如,你想 comments
用 comments
中的 authors
,你可以用 comments.author
:
GET /articles/1?include=author,comments.author HTTP/1.1
Accept: application/vnd.api+json
这种灵活性使得获取正确的资源变得轻而易举,使您可以根据需要调整结果。
稀疏属性
当你使用复合文件时,你的请求可能会变得大且快。尤其是这些请求包含关系中涉及大量数据时。大多数时候你无需在资源中定义每个属性,可你需要诸如作者名字之类的内容。JSON API 为此提供了稀疏属性。
你可以通过设置 fields
请求参数来指定欲获取的字段。格式为 fields[TYPE]
,这样你就可以为每种资源类型指定所需的字段。
GET /articles?include=author&fields[articles]=title,body&fields[people]=name HTTP/1.1
Accept: application/vnd.api+json
这个请求可囊括 articles
资源中的 title
和 body
字段,以及 people
资源中的name
字段。
其他功能
服务端还可以定义更多的功能,这些功能包括排序,分页和过滤。
排序
如果服务端已实现,你可以通过 sort
请求参数对记录进行排序。 默认按照升序排序,你可以通过在字段前加上 -
表示降序排序。
GET /articles?sort=-created,title HTTP/1.1
Accept: application/vnd.api+json
分页
如果服务端支持分页,他将提供一些分页相关的额外元数据。 服务端可以决定如何来分页,可以通过偏移量,或者直接使用页数。 下面的例子中提供了其他页面所需的链接,在 mata 标签中还包含一些其他的元数据。
{
links: {
first: "http://example.com/articles?page=1",
last: "http://example.com/articles?page=262",
prev: "http://example.com/articles?page=261",
next: null
},
meta: {
current_page: 262,
from: 3916,
last_page: 262,
per_page: 15,
to: 3924,
total: 3924
}
}
过滤
该规范对过滤几乎没有说明,只是声明一个名为 filter
的参数,用于在服务器上实现过滤。该实现和具体服务器有关,可以是任何东西。
创建,更新和删除资源
了解文档结构后,创建和更新资源变得轻而易举。它使用标准HTTP谓词来传递请求所需的操作。用于查询的 GET
,用于创建的 POST
,用于(部分)更新的 PATCH
和用于删除资源的 DELETE
。
创建资源
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
属性中。
更新资源
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"
}
}
}
更新资源时,会将请求的字段更新为新值。未包含在请求中的字段不会被更新。
更新关系
可以通过两种方式更新关系。一种是在 PATCH
请求中包含关系, 就想你之前看到的一样;另一种方式是使用指定关系端点。
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
上的一对一关系。如果您想删除关系,传递 null
即可。
如果要更新多对多关系,只需要将关系数据发送到短点即可。会将所有的成员的关系替换为您请求的数据。
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" }
]
}
清除多对多的关系时,只需要将空数组作为数据请求即可。
删除资源
关于删除资源无需赘言,你只需向终端发送一个 DELETE
请求。
DELETE /photos/1 HTTP/1.1
Accept: application/vnd.api+json
了解更多
==========
如果你想了解关于 {json:api} 的细节和使用方法,请查阅 jsonapi.org。他们的标准相当清晰,尽管有许多特性不强求服务端去实现。在他们的网站上,他们也维护了一个 实现 JSON API 的服务端和客户端 清单,它可以帮助你快速在应用中实现。
他们正在制定 1.1 版本的标准,该版本会 100% 兼容 1.0 版本,相对于旧版本,1.1 版本只添加了新的特性,而没有对现有标准进行修改。
{json:api} <3
但愿你已经了解了这个标准为何如此优秀。个人而言,我喜欢它的结构,一致性以及灵活性,它使与 API 交互更加简单。你会一直清楚自己会得到什么,而无需承担请求数据的压力。
正因如此,我们正在开发 将远程 {json:api} 资源映射到 Laravel Eloquent 的扩展,就像模型和集合,和一个使用 Eloquent 模型生成 {json:api} 的扩展。
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
tips:
fractal
支持json-api
,所以如果使用的是dingo/api
可以一键切换https://fractal.thephpleague.com/serialize...