Home Archives Categories Tags Docs

HTTP api 设计格式

发布时间: 更新时间: 总字数:11552 阅读时间:24m 作者: 分享

定义http api 设计格式,使JSON:API更加符合团队的API需求。

状态码描述

204 No Content

如果更新成功,且客户端属性保持最新,服务器必须返回204 No Content状态码。适用于PUT请求,以及仅调整links,不涉及其它属性的POST, DELETE请求

200 OK

如果服务器接受更新,但是在请求指定内容之外做了资源修改,必须响应200 OK以及更新的资源实例,像是向此URL发出GET请求.

201 Created

如果服务器需要创建一些资源, 比如创建用户, 创建用户数据, 创建资源, 默认API的create方法返回这个状态码.

301 Moved Permanently

被请求的资源已永久移动到新位置, 适用于资源link的变更,服务器做出兼容API.

303 See Other

对应当前请求的响应可以在另一个 URI 上被找到,客户端应该使用 GET 方法进行请求, 适用于旧API往新API的兼容.

400 Bad Request

请求体包含语法错误, 出现本错误服务端应该向客户端发送出错描述

适用于:
- 发送了无法转化的请求体

401 Unauthorized

需要验证用户身份,如果服务器就算是身份验证后也不允许客户访问资源,应该响应 403 Forbidden, 适用于未登录检查

403 Forbidden

服务器拒绝执行

适用于:
- 服务到期(比如付费的增值服务等
- 因为某些原因不允许访问(比如被 ban )
- 权限不够,403 状态码

404 Not Found

找不到目标资源

适用于:
- 需要修改的资源不存在

405 Method Not Allowed

不允许执行目标方法,响应中应该带有 Allow 头,内容为对该资源有效的 HTTP 方法

406 Not Acceptable

服务器不支持客户端请求的内容格式(比如客户端请求 JSON 格式的数据,但服务器只能提供 XML 格式的数据)

409 Conflict

请求操作和资源的当前状态存在冲突

410 Gone

被请求的资源已被删除

412 Precondition Failed

服务器在验证在请求的头字段中给出先决条件时,没能满足其中的一个或多个。主要使用场景在于实现并发控制

413 Request Entity Too Large

POST 或者 PUT 请求的消息实体过大

415 Unsupported Media Type

服务器不支持请求中提交的数据的格式

422 Unprocessable Entity

请求格式正确,但是由于含有语义错误,无法响应

适用于:
- 发送了非法的资源

428 Precondition Required

要求先决条件,如果想要请求能成功必须满足一些预设的条件
适用于:
- 缺少了必要的头信息

500 Internal Server Error

服务器遇到了一个未曾预料的状况,导致了它无法完成对请求的处理。

501 Not Implemented

服务器不支持当前请求所需要的某个功能。
501 与 405 的区别是:405 是表示服务端不允许客户端这么做,501 是表示客户端或许可以这么做,但服务端还没有实现这个功能

502 Bad Gateway

作为网关或者代理工作的服务器尝试执行请求时,从上游服务器接收到无效的响应。

503 Service Unavailable

由于临时的服务器维护或者过载,服务器当前无法处理请求。这个状况是临时的,并且将在一段时间以后恢复。如果能够预计延迟时间,那么响应中可以包含一个 Retry-After 头用以标明这个延迟时间(内容可以为数字,单位为秒;或者是一个 HTTP 协议指定的时间格式)。如果没有给出这个 Retry-After 信息,那么客户端应当以处理 500 响应的方式处理它。

适用于: 服务器维护中

错误描述

{
   "message": "Validation Failed",
   "errors": [
     {
       "resource": "Issue",
       "field": "title",
       "code": "missing_field"
     }
   ]
 }

所有错误包括下面信息

  • missing: 说明某个字段的值代表的资源不存在
  • invalid: 某个字段的值非法,接口文档中会提供相应的信息
  • missing_field: 缺失某个必须的字段
  • already_exist: 发送的资源中的某个字段的值和服务器中已有的某个资源冲突,常见于某些值全局唯一的字段,比如 @ 用的用户名(这个错误我有纠结,因为其实有 409 状态码可以表示,但是在修改某个资源时,很一般显然请求中不止是一种错误,如果是 409 的话,多种错误的场景就不合适了)


header头规范

标准头

Content-Type: application/vnd.api+json
Accept: application/vnd.{团队名称}.{版本号: v1, v2, ...}+json

说明:

  • application/vnd.api+json : JSON API 在 IANA 机构完成注册的 MIME 类型
  • application/vnd.{团队名称}.{版本号: v1, v2, …}+json 服务器接收类型

认证头

Authorization: Bearer {用户token}

其他需要注意的内容(建议)

User-Agent: {你需要的内容}

格式

参考: https://github.com/justjavac/json-api-zh_CN

介绍

JSON API 是数据交互规范,用以定义客户端如何获取与修改资源,以及服务器如何响应对应请求。

JSON API设计用来最小化请求的数量,以及客户端与服务器间传输的数据量。在高效实现的同时,无需牺牲可读性、灵活性和可发现性。

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

JSON API服务器支持通过GET方法获取资源。而且必须独立实现HTTP POST, PUT和DELETE方法的请求响应,以支持资源的创建、更新和删除。

JSON API服务器也可以选择性支持HTTP PATCH方法 [RFC5789]和JSON Patch格式 [RFC6902],进行资源修改。JSON Patch支持是可行的,因为理论上来说,JSON API通过单一JSON 文档,反映域下的所有资源,并将JSON文档作为资源操作介质。在文档顶层,依据资源类型分组。每个资源都通过文档下的唯一路径辨识。

规则约定

文档中的关键字, «MUST», «MUST NOT», «REQUIRED», «SHALL», «SHALL NOT», «SHOULD»,
«SHOULD NOT», «RECOMMENDED», «MAY», and «OPTIONAL» 依据RFC 2119
[RFC2119]规范解释。

文档结构

这一章节描述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

每一个资源对象应该有一个唯一标示符,或者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 请求,响应内容包含资源对象集合的关联资源。

顶层的 "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

关联文档

确定API的URL结构时,考虑把所有的资源放置于单一“关联文档»是有用的,在关联文档中,每个资源都被分配唯一路径。在文档顶层,资源依据类型分组。在分类资源集合中,单独资源通过ID索引。其属性和links,依据资源对象结构,唯一分配。

关联文档的概念,用于为资源及资源关系确定合适的URLs。重要的一点,出于不同目标和限制,用于传输资源的不同文档中,关联文档的结构有轻微差异。例如,在关联文档中的资源集当做集合处理,因为元素必须通过ID访问,在传输文档中的资源集当做数组处理,因为顺序比较重要。

资源集合URLs

资源集合的URL应该依据资源类型确定。

例如,”photos”类型的资源集合应该使用这种URL:

/photos

单独资源URLs

资源集应该作为集合,依据资源ID索引。单独资源的URL通过为集合URL添加资源ID生成。

例如,ID为"1"的photo使用这种URL:

/photos/1

多个单独资源的URL通过为集合URL添加逗号分隔的资源IDs列表生成。

例如,IDs为"1", "2", "3"的photos使用这种URL:

/photos/1,2,3

替代性URLs

资源的替代性URLs可以选择在响应中指定,或者通过"href"或URL模板指定。

关联 URLs

添加/links/<relationship-name>到资源URL后面,即得到访问特定资源的关联资源URL。相对路径与资源对象内部结构保持一致。

例如,photo的comments链接集使用这种URL:

/photos/1/links/comments

A photo’s reference to an individual linked photographer will have the URL:
photo的photographer链接使用这种URL:

/photos/1/links/photographer

服务器使用单独资源响应单对象关联,使用资源集合响应多对象关联。

资源获取

资源,或者资源集合,通过向URL发出GET请求获取。

响应内容可以使用如下所示的特点,进一步细化。

过滤

服务器可以选择性支持,依据指定标准进行资源过滤。

通过向资源集合的基准URL添加过滤参数,来支持资源过滤。

例如,下面是请求与特定post关联的所有comments:

GET /comments?posts=1

使用这种方案,单一请求可以使用多过滤器:

GET /comments?posts=1&author=12

这种规范仅支持基于严格匹配的资源过滤。API允许使用的额外过滤器应该在它的侧写中指定。 (见
Extending)

内链资源

服务器可以选择性支持,返回包含主要资源和链接资源对象的复合文档。

默认情况下,后端返回链接主要资源的资源对象。

后端也可以基于请求中include的参数,支持自定义链接资源。参数应该指定一个或者多个,相对于主要资源的相对路径。如果指定参数值,只有请求的链接资源,应该随主要资源返回。

例如,comments可以通过post请求:

GET /posts/1?include=comments

为请求链接到其他资源的资源,需要指定每个关联的点分隔路径。

GET /posts/1?include=comments.author

注意:对comments.author的请求,在响应中不应该自动包含comments资源(尽管comments也需要显式查询,以获取authors响应请求)。

多链接资源可以使用点分隔列表请求:

GET /posts/1?include=author,comments,comments.author

稀疏字段

服务器可以选择性支持,仅返回资源对象的指定字段。

后端可以基于fields参数,以支持返回主要资源的指定字段。

GET /people?fields=id,name,age

后端可以基于fields[TYPE]参数,以支持返回任意类型资源的特定字段。

GET /posts?include=author&fields[posts]=id,title&fields[people]=id,name

若没有指定类型对象的字段,或者后端不支持fieldfields[TYPE]参数,后端会默认返回资源对象的所有字段。

后端可以选择总是返回有限的,未指定的字段集,例如id or href.

注意: fieldsfields[TYPE]不能混合使用。如果使用后者,那么必须与主要资源类型同时使用。

排序

服务器可以选择性支持,基于特定标准对资源集合排序。

后端基于sort参数,以支持主要资源类型的排序。

GET /people?sort=age

后端支持多字段排序,将sort值设置为点分隔值即可。排序标准用以获取特定顺序。

GET /people?sort=age,name

默认排序方式为升序排序。任意排序字段,使用-前缀指定降序排序。

GET /posts?sort=-created,title

上面的示例应该首先返回最新的posts。同一天创建的posts,依据title值进行字母升序排列。

后端基于sort[TYPE]参数,以支持对任意资源类型排序。

GET /posts?include=author&sort[posts]=-created,title&sort[people]=name

如果没有指定排序方式,或者后端不支持sortsort[TYPE],后端将会返回使用重复算法排序的资源对象。换言之,资源应该总是以相同顺序返回,即使排序规则没有指定。

注意:sortsort[TYPE]不能混用。如果使用后者,必须与主要资源一同使用。

创建,更新,删除资源

服务器可能支持资源获取,创建,更新和删除。

服务器允许单次请求,更新多个资源,如下所述。多个资源更新必须完全成功或者失败,不允许部分更新成功。

任何包含内容的请求,必须包含Content-Type:application/vnd.api+json请求头。

创建资源

支持资源创建的服务器,必须支持创建单独的资源,可以选择性支持一次请求,创建多个资源。

向表示待创建资源所属资源集的URL,发出POST请求,创建一个或多个资源。

创建单独资源

创建单独资源的请求必须包含单一主要资源对象。

例如,新photo可以通过如下请求创建:

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

{
  "photos": {
    "title": "Ember Hamster",
    "src": "http://example.com/images/productivity.png"
  }
}
创建多个资源

创建多个资源的请求必须包含主要主要资源集合。

例如,多个photos通过如下请求创建:

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

{
  "photos": [{
    "title": "Ember Hamster",
    "src": "http://example.com/images/productivity.png"
  }, {
    "title": "Mustaches on a Stick",
    "src": "http://example.com/images/mustaches.png"
  }]
}
响应
201 状态码

服务器依据HTTP semantics规范,响应成功的资源创建请求。

当一个或多个资源创建成功,服务器返回201 Created状态码。

响应必须包含Location头,用以标示请求创建所有资源的位置。

如果创建了单个资源,且资源对象包含href键,Location URL必须匹配href值。

响应必须含有一个文档,用以存储所创建的主要资源。如果缺失,客户端则判定资源创建时,传输的文档未经修改。

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

{
  "photos": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "href": "http://example.com/photos/550e8400-e29b-41d4-a716-446655440000",
    "title": "Ember Hamster",
    "src": "http://example.com/images/productivity.png"
  }
}
其它响应

服务器可能使用其它HTTP错误状态码反映错误。客户端必须依据HTTP规范处理这些错误信息。如下所述,错误细节可能会一并返回。

客户端生成 IDs

请求创建一个或多个资源时,服务器可能接受客户端生成IDs。IDs必须使用"id"键来指定,其值必须正确生成,且为格式化的*UUID*。

例如:

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

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

更新资源

支持资源更新的服务器必须支持单个资源的更新,可以选择性的支持单次请求更新多个资源。

向表示单独资源或多个单独资源的URL发出PUT请求,即可进行资源更新。

更新单独资源

为更新单独资源,向表示资源的URL发出PUT请求。请求必须包含一个顶层资源对象。

例如:

PUT /articles/1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "articles": {
    "id": "1",
    "title": "To TDD or Not"
  }
}
更新多个资源

向表示多个单独资源(不是全部的资源集合)的URL发出PUT请求,即可更新多个资源。请求必须包含顶层资源对象集合,且每个资源具有“id"元素。

例如:

PUT /articles/1,2
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "articles": [{
    "id": "1",
    "title": "To TDD or Not"
  }, {
    "id": "2",
    "title": "LOL Engineering"
  }]
}
更新属性

要更新资源的一个或多个属性,主要资源对象应该只包括待更新的属性。资源对象缺省的属性将不会更新。

例如,下面的PUT请求,仅会更新article的titletext属性。

PUT /articles/1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "articles": {
    "id": "1",
    "title": "To TDD or Not",
    "text": "TLDR; It's complicated... but check your test coverage regardless."
  }
}
更新关联
更新单对象关联

单对象关联更新,可以在PUT请求资源对象中包含links键,从而与其它属性一起更新。

例如,下面的PUT请求将会更新article的titleauthor属性:

PUT /articles/1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "articles": {
    "title": "Rails is a Melting Pot",
    "links": {
      "author": "1"
    }
  }
}

若要移除单对象关联,指定null作为值即可。

另外,单对象关联也可以通过它的关联URL访问。

向关联URL发出带有主要资源的POST请求,即可添加单对象关联。

例如:

POST /articles/1/links/author
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "people": "12"
}

向关联URL发出DELETE请求,即可删除单对象关联。例如:

DELETE /articles/1/links/author
更新多关联对象

更新多对象关联,可以在PUT请求中资源对象包含links键,从而与其它属性一起更新。

例如,下面PUT请求完全替换article的tags

PUT /articles/1
Content-Type: application/vnd.api+json
Accept: application/vnd.api+json

{
  "articles": {
    "id": "1",
    "title": "Rails is a Melting Pot",
    "links": {
      "tags": ["2", "3"]
    }
  }
}

若要移除多对象关联,指定空数组[]为值即可。

在分布式系统中,完全替换一个数据集合并不总是合适。替换方案是允许单独的添加或移除关联。

为促进细化访问,多对象关联也可以通过关联URL访问。

向关联URL发出带有主要资源的POST请求,即可添加多对象关联。

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

{
  "comments": ["1", "2"]
}

向关联URL发出DELETE请求,即可删除多对象对象关联。例如:

DELETE /articles/1/links/tags/1

向关联URL发出DELETE请求,即可删除多个多对象对象关联。例如:

DELETE /articles/1/links/tags/1,2

响应

204 No Content

如果更新成功,且客户端属性保持最新,服务器必须返回204 No Content状态码。适用于PUT请求,以及仅调整links,不涉及其它属性的POST, DELETE请求。

200 OK

如果服务器接受更新,但是在请求指定内容之外做了资源修改,必须响应200 OK以及更新的资源实例,像是向此URL发出GET请求。

其它响应

服务器使用其它HTTP错误状态码反映错误。客户端必须依据HTTP规范处理这些错误信息。如下所述,错误细节可能会一并返回。

资源删除

向资源URL发出DELETE请求即可删除单个资源。

DELETE /photos/1

服务器可以选择性的支持,在一个请求里删除多个资源。

DELETE /photos/1,2,3
响应
204 No Content

如果删除请求成功,服务器必须返回204 No Content 状态码。

其它响应

服务器使用其它HTTP错误状态码反映错误。客户端必须依据HTTP规范处理这些错误信息。如下所述,错误细节可能会一并返回。

Errors

错误对象是特殊化的资源对象,可能在响应中一并返回,用以提供执行操作遭遇问题的额外信息。在在JSON API文档顶层,"errors"对应值即为错误对象集合,此时文档不应该包含其它顶层资源。

错误对象可能有以下元素:

  • "id" - 特定问题的唯一标示符。
  • "href" - 提供特定问题更多细节的URI。
  • "status" - 适用于这个问题的HTTP状态码,使用字符串表示。
  • "code" - 应用特定的错误码,以字符串表示。
  • "title" - 简短的,可读性高的问题总结。除了国际化本地化处理之外,不同场景下,相同的问题,值是不应该变动的。
  • "detail" - 针对该问题的高可读性解释。
  • "links" - 可以在请求文档中取消应用的关联资源。
  • "path" - 关联资源中相关属性的相对路径。在单资源或单类型资源中出现的问题,这个值才是合适的。

额外的元素可以在错误对象中指定。

实现接口可以选择使用其它的errors媒体类型。

PATCH Support

JSON API服务器可以选择性支持,遵循JSON Patch规范[RFC6902]的HTTP PATCH请求。上面提到使用POST, PUTDELETE进行的操作,JSON Patch都拥有等效操作。从这里开始,PATCH请求发出的JSON Patch操作,都被简单的称作“PATCH«操作。

PATCH请求必须声明Content-Type:application/json-patch+json头。

PATCH操作必须作为数组发送,以遵循JSON Patch规范。服务器可能会限制顶层数组类型,顺序和操作数量。

请求 URLs

每个PATCH请求的URL应该映射待更新的资源或关联。

PATCH操作内的每个"path"应该相对于请求URL。请求URL和PATCH操作的"path"是附加的,合并后获取特定资源,集合,属性,或者关联目标。

PATCH操作可以在API的根URL使用。此时,PATCH操作的"path"必须包含完整的资源URL。API表示的任意资源都可以进行常规的»fire hose»更新。如上所述,服务器可能会限制类型,排序和批量操作数量。

创建资源with PATCH

要创建资源,执行"add"操作, "path"指向对应资源集合的末尾 ("/-")。"value"必须包含一个资源对象。

比如,新photo通过如下请求创建:

PATCH /photos
Content-Type: application/json-patch+json
Accept: application/json

[
  { 
    "op": "add", 
    "path": "/-", 
    "value": {
      "title": "Ember Hamster",
      "src": "http://example.com/images/productivity.png"
    }
  }
]

更新属性with PATCH

要更新属性,执行"replace" 操作,"path"值指定属性名。

例如,下面请求只更新/photos/1src值。

PATCH /photos/1
Content-Type: application/json-patch+json

[
  {
  "op": "replace",
  "path": "/src",
  "value": "http://example.com/hamster.png"
 }
]

更新关联with PATCH

要更新关联,向对应的关联URL发出合适的PATCH操作即可。

服务器可能支持更高层级的更新,像资源的URL(甚至是API的根URL)。如上所述,请求URL和每个操作的"path"是附加的,合并后获得特定关联URL目标。

关联更新with PATCH

要更新单对象关联,对指向关联的URL和"path" 执行"replace"操作。

例如:下面请求更新article的author

PATCH /article/1/links/author
Content-Type: application/json-patch+json

[
 {
  "op": "replace",
  "path": "/",
  "value": "1"
 }
]

要移除单对象关联,对关联执行remove操作。例如:

PATCH /article/1/links/author
Content-Type: application/json-patch+json

[
  { 
    "op": "remove", 
    "path": "/" 
  }
]
更新多对象关联 with PATCH

尽管在GET响应中,多对象关联以JSON数组形式表示,但是更新时更像是集合。

要添加元素到多对象关联,执行指向关联URL的"add" 请求。由于操作指向集合末尾, "path" 必须以"/-"结尾。

例如,考虑下面的GET请求:

GET /photos/1
Content-Type: application/vnd.api+json

{
  "links": {
    "comments": "http://example.com/comments/{comments}"
  },
  "photos": {
    "id": "1",
    "href": "http://example.com/photos/1",
    "title": "Hamster",
    "src": "images/hamster.png",
    "links": {
      "comments": [ "1", "5", "12", "17" ]
    }
  }
}

PATCH请求执行add操作,即可将comment 30 转移到这个photo。

PATCH /photos/1/links/comments
Content-Type: application/json-patch+json

[
  { 
    "op": "add", 
    "path": "/-", 
    "value": "30"
  }
]

要移除多对象关联,对指向关联对象的URL执行"remove"操作。因为操作目标是元素集合,"path"必须以"/<id>"结尾。

比如,要移除photo的comment 5,执行"remove"操作:

PATCH /photos/1/links/comments
Content-Type: application/json-patch+json

[
  { 
    "op": "remove", 
    "path": "/5" 
  }
]

删除资源with PATCH

要删除资源,对指向资源的 URL 和"path"执行 "remove" 操作。

例如,photo 1 能使用下面请求删除:

PATCH /photos/1
Content-Type: application/json-patch+json
Accept: application/vnd.api+json

[
  { 
    "op": "remove",
    "path": "/"
  }
]

响应

204 No Content

PATCH请求成功,客户端当前的属性保持最新,服务器必须响应204 No Content 状态码。

200 OK

如果服务器接受更新,但是在请求指定内容之外做了资源修改,必须响应200 OK以及更新的资源实例。

服务器必须指定Content-Type:application/json头。响应内容必须包含JSON对象数组,每个对象必须遵循JSON API媒体类型(application/vnd.api+json)。数组中的响应对象必须有序,并且对应请求文档操作。

例如,一个请求以分离操作,创建两个photos。

PATCH /photos
Content-Type: application/json-patch+json
Accept: application/json

[
  { 
    "op": "add", 
    "path": "/-", 
    "value": {
      "title": "Ember Hamster",
      "src": "http://example.com/images/productivity.png"
    }
  },
  { 
    "op": "add", 
    "path": "/-", 
    "value": {
      "title": "Mustaches on a Stick",
      "src": "http://example.com/images/mustaches.png"
    }
  }
]

响应内容在数组中包含对应的JSON API文档。

HTTP/1.1 200 OK
Content-Type: application/json

[
  {
    "photos": [{
      "id": "123",
      "title": "Ember Hamster",
      "src": "http://example.com/images/productivity.png"
    }]
  }, {
    "photos": [{
      "id": "124",
      "title": "Mustaches on a Stick",
      "src": "http://example.com/images/mustaches.png"
    }]
  }
]
其它响应

当服务器执行PATCH请求时出现一个或多个问题,应该在响应中指定最合适的HTTP状态码。客户端依据HTTP规范解析错误。

服务器可以选择在第一个问题出现时,立刻终止PATCH 操作,或者继续执行,遇到多个问题。例如,服务器可能多属性更新,然后返回在一个响应里返回多个校验问题。

当服务器单个请求遇到多个问题,响应中应该指定最通用可行的HTTP错误码。例如,400 Bad Request适用于多个4xx errors,500 Internal Server Error适用于多个5xx errors。

服务器可能会返回与每个操作对应的错误对象。服务器需要指定Content-Type:application/json头,响应体必须包含JSON对象数组,每个对象必须遵循JSON API媒体类型 (application/vnd.api+json)。数组中的响应对象,必须是有序,且与请求文档中的操作相对应。每个响应对象应该仅包含error对象,当错误发生时,没有操作会完全成功。每个特定操作的错误码,应该在每个error对象 "status" 元素反映。

服务器可能会使用遵循HTTP 1.1规范的HTTP 缓存头 (ETag, Last-Modified)。

相关文章
最近更新
最新评论
加载中...