REST 概念来源

  网络应用程序,分为前端和后端两个部分。当前的发展趋势,就是前端设备层出不穷(手机、平板、桌面电脑、其他专用设备...)。 因此,必须有一种统一的机制,方便不同的前端设备与后端进行通信。这导致 API 构架的流行,甚至出现"API First"的设计思想。

2000 年,Roy Thomas Fielding 博士在他那篇著名的博士论文 《Architectural Styles and the Design of Network-based Software Architectures》中提出了几种软件应用的架构风格。 REST 作为其中的一种架构风格在这篇论文的第5章中进行了概括性的介绍。

REST 是一种很笼统的概念,它代表一种架构风格。 对于多个 Web 应用采用的架构,我们只能说其中某一个比其它的更具有 REST 风格, 而不能简单粗暴地说:“它采用了 REST 架构而其它的没有”。 为了将 REST 真正地落地,Lenoard Rechardson & Sam Ruby 在《RESTful Web Services》一书中 提出了一种名为“面向资源的架构(ROA: Resource Oriented Architecture)”。 该书中介绍了一些采用 ROA 架构的 Web 服务应该具备的基本特征。

RESTful Web API 设计只是 REST 风格架构设计中的一个环节,并没有统一的标准。下面介绍的是一些比较没有争议的实践原则。

实践原则

1.版本化你的 API

  应该尽量将 API 部署在专用域名之下。

    https://api.example.com

  如果确定 API 很简单,不会有进一步扩展,可以考虑放在主域名下。

    https://example.org/api/

  应该将 API 的版本号放入 URL。

    https://api.example.com/v1/

  另一种做法是,将版本号放在 HTTP 头信息中,但不如放入 URL 方便和直观。Github 采用这种做法。

2.URI 使用名词和 ID 而不是动词

  在 RESTful 架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词, 而且所用的名词往往与数据库的表格名对应。 一般来说,数据库中的表都是同种记录的"集合"(collection),所以 API 中的名词也应该使用复数。

举例来说,有一个 API 提供动物园(zoo)的信息,还包括各种动物和雇员的信息,则它的路径应该设计成下面这样。

    https://api.example.com/v1/zoos
https://api.example.com/v1/animals
https://api.example.com/v1/employees

3.使用 HTTP 协议标准动词改变状态

  使用 PUT, POST 和 DELETE 方法 而不是 GET 方法来改变状态。 对于资源的具体操作类型,由 HTTP 动词表示。

  常用的 HTTP 动词有下面五个(括号里是对应的 SQL 命令)。

    GET(SELECT):从服务器取出资源(一项或多项)。
POST(CREATE):在服务器新建一个资源。
PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
DELETE(DELETE):从服务器删除资源。

  还有两个不常用的 HTTP 动词。

    HEAD:获取资源的元数据。
OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。

  下面是一些例子。

    GET /zoos:列出所有动物园
POST /zoos:新建一个动物园
GET /zoos/ID:获取某个指定动物园的信息
PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)
PATCH /zoos/ID:更新某个指定动物园的信息(提供该动物园的部分信息)
DELETE /zoos/ID:删除某个动物园
GET /zoos/ID/animals:列出某个指定动物园的所有动物
DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物

4.过滤信息不涉及状态改变

  如果记录数量很多,服务器不可能都将它们返回给用户。API 应该提供参数,过滤返回结果。 常用的过滤包括分页、排序等等。 下面是一些常见的参数。

    ?limit=10:指定返回记录的数量
?offset=10:指定返回记录的开始位置。
?page=2&per_page=100:指定第几页,以及每页的记录数。
?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
?animal_type_id=1:指定筛选条件

  参数的设计允许存在冗余,即允许 API 路径和 URL 参数偶尔有重复。 比如,GET /zoo/ID/animals 与 GET /animals?zoo_id=ID 的含义是相同的。

5.使用 Http 头声明请求和响应的格式

  在客户端和服务端,双方都要知道通讯的格式,格式在 HTTP-Header 中指定

    Content-Type 定义请求格式,比如 URL 格式
Accept 定义系列可接受的响应格式,JSON,XML 等等

  这个并不强制,实践中也可以通过参数来指定返回内容的格式

6.优先使用 JSON 格式返回结果

  当设计 API 返回结果时,优先使用 JSON 格式,但不强制。 当请求的 URL 表明的是一个集合时,则返回结果为数组形式。 例如:

        {
"data":[
{
"login": "jerry1",
"id": 1,
"avatar_url": "https://...."
},
{
"login": "jerry2",
"id": 2,
"avatar_url": "https://...."
},
{
"login": "jerry3",
"id": 3,
"avatar_url": "https://....",
}
]
}

  当请求为单个对象时,则返回结果为 MAP 形式。例如,访问 https://api.test.com/users/test 时:

        {
"login": "jerry4",
"id": 1,
"avatar_url": "https://avatars.githubusercontent.com/u/1?v=3"
}

7.使用超媒体链接来组织文档

  Hypermedia as the Engine of Application State 超媒体作为应用状态的引擎,超文本链接可以建立更好的文本浏览体验。

  RESTful API 最好能做到 Hypermedia,即返回结果中提供链接,连向其他 API 方法,使得用户不查文档,也知道下一步应该做什么。

  比如,当用户向 api.example.com 的根目录发出请求,会得到这样一个文档。

        {
"link": {
"rel": "collection https://www.example.com/zoos",
"href": "https://api.example.com/zoos",
"title": "List of zoos",
"type": "application/vnd.yourformat+json"
}
}

  上面代码表示,文档中有一个 link 属性,用户读取这个属性就知道下一步该调用什么 API 了。 rel表示这个 API 与当前网址的关系(collection 关系,并给出该 collection 的网址), href 表示 API 的路径,title 表示 API 的标题,type 表示返回类型。

Hypermedia API 的设计被称为 HATEOAS。Github 的 API 就是这种设计,访问 api.github.com 会得到一个所有可用 API 的网址列表。

        {
"current_user_url": "https://api.github.com/user",
"authorizations_url": "https://api.github.com/authorizations",
// ...
}

从上面可以看到,如果想获取当前用户的信息,应该去访问 api.github.com/user,然后就得到了下面结果。

        {
"message": "Requires authentication",
"documentation_url": "https://developer.github.com/v3"
}

8.使用 Http 状态码处理错误

  如果你的 API 没有错误处理是很难的,只是返回 500 和出错堆栈不一定有用

  Http 状态码提供 70 个出错,我们只要使用 10 个左右:

    200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
204 NO CONTENT - [DELETE]:用户删除数据成功。
400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
403 Forbidden - [*] 表示用户得到授权(与 401 错误相对),但是访问是被禁止的。
404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求 JSON 格式,但是只有 XML 格式)。
410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。

  使用详细的错误包装错误:

        {
"errors":[
{
"userMessage": "Sorry, the requested resource does not exist",
"internalMessage": "No car found in the database",
"code": 34,
"more info": "http://dev.mwaysolutions.com/blog/api/v1/errors/12345"
}
]
} just here , jerry

RESTful Web API 实践的更多相关文章

  1. 对RESTful Web API的理解与设计思路

    距离上一篇关于Web API的文章(如何实现RESTful Web API的身份验证)有好些时间了,在那篇文章中提到的方法是非常简单而有效的,我在实际的项目中就这么用了,代码经过一段时间的磨合,已经很 ...

  2. 我所理解的RESTful Web API [Web标准篇]

    REST不是一个标准,而是一种软件应用架构风格.基于SOAP的Web服务采用RPC架构,如果说RPC是一种面向操作的架构风格,而REST则是一种面向资源的架构风格.REST是目前业界更为推崇的构建新一 ...

  3. 我所理解的RESTful Web API [设计篇]

    <我所理解的RESTful Web API [Web标准篇]>Web服务已经成为了异质系统之间的互联与集成的主要手段,在过去一段不短的时间里,Web服务几乎清一水地采用SOAP来构建.构建 ...

  4. ASP.NET Web API实践系列04,通过Route等特性设置路由

    ASP.NET Web API路由,简单来说,就是把客户端请求映射到对应的Action上的过程.在"ASP.NET Web API实践系列03,路由模版, 路由惯例, 路由设置"一 ...

  5. About Restful Web Api Something.

    这种轻量级的服务架构目前来说还是比较流行的,比如微信的公众平台的接口开发就是一个很好的案例,提到restful那么他到底是一个什么样的东西? REST(Representational State T ...

  6. 【ASP.NET MVC 学习笔记】- 19 REST和RESTful Web API

    本文参考:http://www.cnblogs.com/willick/p/3441432.html 1.目前使用Web服务的三种主流的方式是:远程过程调用(RPC),面向服务架构(SOA)以及表征性 ...

  7. RESTful Web API 理解

    REST 是一种应用架构风格,不是一种标准,是面向资源架构(ROA)风格,与具体技术平台无关,REST架构的应用未必建立在Web之上,与之对应的是传统的Web Service 采用的面向操作的RPC架 ...

  8. ASP.NET Web API实践系列07,获取数据, 使用Ninject实现依赖倒置,使用Knockout实现页面元素和视图模型的双向绑定

    本篇接着上一篇"ASP.NET Web API实践系列06, 在ASP.NET MVC 4 基础上增加使用ASP.NET WEB API",尝试获取数据. 在Models文件夹下创 ...

  9. ASP.NET Web API实践系列05,消息处理管道

    ASP.NET Web API的消息处理管道可以理解为请求到达Controller之前.Controller返回响应之后的处理机制.之所以需要了解消息处理管道,是因为我们可以借助它来实现对请求和响应的 ...

随机推荐

  1. Simple2D-26 Simple2D 最后的工作,开发结束

    开始的时候打算将 Simple2D 做成一个库的,但现在没有那个功夫了. 要渲染顶点数据,就必须将渲染函数放置到 glClear( ) 函数和 SwapBuffers( ) 函数之间,但又不希望开发时 ...

  2. ncodeURIComponent() 函数 vue内容

    ncodeURIComponent() 函数 编辑 encodeURIComponent() 函数[1]  作用:可把字符串作为URI 组件进行编码.其返回值URIstring 的副本,其中的某些字符 ...

  3. jquery实现背景图片动态适应

    背景 在我的一个项目中用到了背景图片,发现其中有一个问题,当页面长度动态变化时,原来能占满全部内容背景的图片会变得不能占满全部背景.如下图的效果: 这是正常的,背景图片占满全屏 当页面内容变长出现了滚 ...

  4. SSM总结

    1    报错: cvc-complex-type.2.4.a: Invalid content was found starting with element 'async-supported'.  ...

  5. unity VideoPlayer

    Events(事件) started:在调用play()后立刻调用 prepareCompleted:播放器准备完成时 seekCompleted:缓冲完成时

  6. C++17尝鲜:类模板中的模板参数自动推导

    模板参数自动推导 在C++17之前,类模板构造器的模板参数是不能像函数模板的模板参数那样被自动推导的,比如我们无法写 std::pair a{1, "a"s}; // C++17 ...

  7. Rxjs 修改Observable 里的值

    有这么一个对象c$: Observable<any> 修改里边的值: 声明一个subject subject: Subject<any>; 在ngOnInit()中进行初始化 ...

  8. 判断是否有TrueType字体

    function IsTrueTypeAvailable : bool;var {$IFDEF WIN32}  rs : TRasterizerStatus; {$ELSE}  rs : TRaste ...

  9. scala-- 内建控制结构

    内建控制结构 ​ scala 内建的控制结构很少,只有 if while for try match 和函数调用 几种. 因为scala 从语法层面支持函数字面量.几乎所有的scala控制结构都会产生 ...

  10. 如何勾选 servlet如何获取?

    1.jsp中checkbox <form action="Test"> <% for(int i = 0 ; i < 10 ; i++){ %> &l ...