1.Foreword
URI templates:they are like URLs with variables in them that can be replaced
with values to form a usable URL
类似带路径参数的URL
example:
![](https://i-blog.csdnimg.cn/blog_migrate/25018ce0f3167231e6a064351a97e17f.png)
The HTTP methods GET, POST, PUT or PATCH, and DELETE can be used with these templates to read, create, update, and delete description resources
HTTP方法GET,POST,PUT,PATCH和DELETE 可以用来对资源做 读,创建,更新和删除操作
2.Introduction
当你设计接口,你应该站在用户的角度去考虑。作为API的提供者,可能只需要实现一个或者几个API,但是作为使用者却需要接触到大量的API。因此遵循某一个标准开发比开发你自己用的接口十分重要。
3.Web API and REST
4.HTTP and REST : A Data-oriented Design Paradigm
API Design Elements
The following aspects of API design are all important, and together they defne your API:
- The representations of your resources—this includes the definition of the fields in the resources (assuming your resource representations are structured, rather than streams of bytes or characters), and the links to related resources.
- The use of standard (and occasionally custom) HTTP headers.
- The URLs and URI templates that defne the query interface of your API for locating resources based on their data.
- Required behaviors by clients—for example, DNS caching behaviors, retry behaviors, tolerance of fields that were not previously present in resources, and so on.
- 资源的表现形式——包括资源字段的定义和连接相关资源
- 使用标准的(有时需要自定义)的HTTP headers
- URL和URI模版定义了定位数据资源的查询接口
- 客户端所需的行为——例如,DNS缓存行为、重试行为、对以前没有在资源中出现的字段的容忍等等
Representation是指 客户端从服务端获取或者发送web资源时返回的数据
在REST模式下,网络资源具有潜在的状态在客户端和服务端之间流动的时候才会表现出来
Use JSON
当今最流行的数据资源表现形式就是JSON。
JSON流行的原因是易于理解,方便与程序数据结构结合。
JSON并不完美。JSON仅支持部分数据类型(Null,Boolean,Number,String)一些常见的数据类型JSON并不支持例如Dates,times,URLs等。
Keep your JSON simple
保持JSON简洁、直观、最好能够不言自明
例子:
![](https://i-blog.csdnimg.cn/blog_migrate/4d85f57dae6951950f539d86e1511972.png)
Include links
很多情况下,数据资源不仅仅包含简单的属性还不包含和其他数据的关系。
下面以狗与狗主人的关系为例构建JSON:
![](https://i-blog.csdnimg.cn/blog_migrate/9c7c712a1929a3cb88e11512eaa88a38.png)
![](https://i-blog.csdnimg.cn/blog_migrate/8769394d4fa3fd9287f986526e1e763d.png)
![](https://i-blog.csdnimg.cn/blog_migrate/9087141cd4257c40ac077032332830c1.png)
在关系中使用连接表达有以下好处:
- 不用再使用程序构造跳转链接,省去debug
- 不需要猜测关联的资源的地址
5.Designing URLs
URL中使用名词,不要使用动词!
Designing entity URLs
永久链接——对某个资源比如Joe这个人来说 指向他的永久链接应该是
https://dogtracker.com/person/
e9cdcf7a-25b3-11e5-9aec-34363bd0ac10在链接后使用UUID作为唯一标识。这样虽然对客户端使用者不友好,但是由于这种连接不是给客户端使用的所以没有问题
给客户端的连接可能是类似以下的链接
这种链接对人很友好,但是当Joe改名字时候,这个链接就会失去意义。
重命名的两难选择
使用唯一标识的时候URL并不对人友好,使用可变更字段name的时候URL虽然友好但是却有可能随着时间的推移失去意义。
书里提到的解决方法是将旧的链接以重定向的方法定向到新的链接上。
https://dogtracker.com/person/
Jack上,而当客户端调用这个链接时候服务器会接受到唯一标识的链接
https://dogtracker.com/person/e9cdcf7a-25b3-11e5-9aec-34363bd0ac10
Design query URLs
When API designers defne the URI templates for their API, they are in fact designing a custom query language for the API.
API的设计者在设计API的URL模版时,实际上是在定义用户对于资源的查询语句
两种URL风格的对比:
![](https://i-blog.csdnimg.cn/blog_migrate/909872df0dbc84ef5097b00bd744f7e3.png)
构建具有关系的查询URL
/{relationship-name}[/{resource-id}]/…/{relationship-name}[/{resource-id}]
{resource-id}只有在前面的relationship-name资源下是多个资源的时候才有意义
例如:/persons/5678/dogs 表示 所有人里id为5678的人名下的所有的狗
另一种URL的表现方式:
/{relationship-name}[;{selector}]/…/{relationship-name}[;{selector}]
仍然以 /persons/5678/dogs为例,以下表达方式同义:
/persons;5678/dogs
/persons;id=5678/dogs
/persons;name=JoeMCarraclough/dogs
/persons;name=JoeMCarraclough/dogs
{selector}值对前面的relationship的一种筛选方式。这种参数形式被称为路径参数(path parameters)或是矩阵参数(matrix parameters)
对于复杂的查询条件
使用URL传参 类似于
/persons/5678/dogs?color=red&location=park
可以结合复杂查询和路径参数一起使用来构建API
What about responses that don’t involve persistent resources?
对于计算、翻译或者转换这类请求,可能调用的数据并不用持久化,那么这类URLs应该怎么设计?
以需要把100欧元转换为人民币为例,可以使用如下url:
/monetary-amount?quantity=100&unit=EUR&in=CNY
或者更简单的形式
/monetary-amount/100/EUR/CNY
或者在HTTP请求头中添加相关头信息
![](https://i-blog.csdnimg.cn/blog_migrate/1a52c8a40c269599227ac8f38ebbee5e.png)
或者以如下的POST形式
![](https://i-blog.csdnimg.cn/blog_migrate/9f88d1c9db62f7e1426c3579ff6c90cc.png)
只有当POST是你最佳的请求的时候再使用,否则最好能使用GET请求来处理这类问题
引用别人的翻译:
POST返回的结果可能无法再server端缓存;你是在构建一个计算的过程,而非资源的表述,如何理解?就像数据库操作中的‘store procedure’,你可以使用,并且功能强大,但是接口变得复杂,逻辑变得耦合
6.More on Representation Design
Include self-reference and kind properties
包含指向自己的链接和类型属性,self-reference有利于不借助上下文定位资源位置而不用再构建指向该资源的链接,kind properties有利于明确资源类型帮助客户端明确是否可以处理这种类型的数据。
How should I represent collections
集合也作为一种资源,所以我们对于简单JSON对象的要求同样也使用于集合
![](https://i-blog.csdnimg.cn/blog_migrate/6332276c411a4b684b98c34ee978ece8.png)
也可以使用更简介的JSON形式
![](https://i-blog.csdnimg.cn/blog_migrate/70de322554922d99d641d5e99c54d80f.png)
这种形式只包含第一种方案的集合部分
Paginated collections
当返回某一类集合数据量很大的时候需要进行分页处理。
下面给出一种分页的数据例子:
![](https://i-blog.csdnimg.cn/blog_migrate/a6a5d5daed78d091e1d3deee21131055.png)
![](https://i-blog.csdnimg.cn/blog_migrate/9e826c038b0d54fa38b3303b45c7f933.png)
Supporting multiple formats
现在大多数API的数据传递都是通过JSON来传递的,但是还有其他的传递方式例如XML,或者你自己定义的数据格式,如果要支持多数据格式传递你应该支持更多的标准HTTP Accept header
如果你只使用JSON,那你应该加入PATCH方法,而不是一味的使用PUT来更新你的资源!
PATCH使用方法,具体详见以下链接(原版是英文的)
What about property names?
使用snake_case还是camelCase一直有所争论
JavaScript, Java, and Objective-C programmers tend to favor camelCase, while Python
and Ruby programmers tend to favor snake_case, with PHP being split by sub-communities.
选择团队适合的方式即可
尽量避免使用容易引起歧义的字符或者容易引发问题的字符,比如连字符-,在属性中避免使用url中可能出现的字符 /\=:;,.?#<>@等等,也尽量避免各种编程语言和全局环境中的保留字关键字等等。
Date and time formats
并没有确定的规范来格式化日期时间,ISO 8601 standard和Unix的时间格式等都是可作为参考的标准。
7.Chatty APIs
如果你的API太过于复杂混乱,那么不是因为你使用了REST而是因为你使用了错误的方法表达错误的资源。
Pagination and partial response
返回部分数据给前端,一些大公司的API
/dogs?fields=name,color,location
field后表示需要加入到response中的数据
这样做有如下几点好处:
- 易于阅读
- 应用开发者可以在需要的时候返回选择的信息(原句:A application developer can select just the information an app needs at a given time.)
- 减少带宽问题,这对移动端应用很重要!
对于分页的URL一些大公司的构建方式
8.Handling Errors
利用HTTP状态码处理错误请求十分重要。
状态码不是孤立的——他们是HTTP响应消息的一部分,其中包括状态码,header以及可能有数据返回,不同状态码包含相应的header。
如果出现错误,应该返回一个错误信息给你的用户,易于用户理解错误并且更正错误。
9.Modeling Actions
通过URL触发一些操作,例如StopRequest, StartRequest, PauseRequest, ResumeRequest
这章没太理解说的是什么。。。
10.Authentication
多年前,人们一直在争论使用哪种认证授权方式?但是现在你应该使用OAuth2。
使用OAuth 2.0意味着暴露api的web或移动应用程序不需要共享密码。
OAuth2相关链接:
11.Complement with an SDK
12.Versioning
对于API是否应该对多版本进行支持一直都有争议,网上给出的可能是各种相互矛盾的结果。
本书给出以下两点建议:
- 不使用任何的多版本API也许是一种明智的做法(原文:Doing nothing at all for API versioning is an intelligent approach that is getting more attention)
- 链接和URL中的版本信息让其显得臃肿(原文:Links and version identifers in URLs make awkward bedfellows)
Doing nothing for versioning
我们都知道APIs会随着时间演进但是还要保持不打破客户端的使用,这是一个挑战。所以看起来什么都不做并不是明智之举。在以往的API里,经常能够在URL路径中发现类似于/v1这样的部分,预期想要改变它们但是从未变动,是什么造成了这样的事情!?
对于API来说许多变化都可以以向后兼容的方式来实现,如果你可以通过向后兼容来代替多版本那么你一定要这么做。
这一段以本书作者的经验之谈提出了不要对URL进行多版本发布。
当然这样还能让你避免在文档中解释v1这个部分的意义。
Links and version identifers in URLs make awkward bedfellows
如果你不得不发布多版本的API,那么你会面临是把版本信息插入URL中还是加入到header中的抉择。如果你的JSON中用到了links,你会发现把版本信息存到header里更方便。
可以选择在header中加入Accept-Version或者其他简单的header作为版本标识。
13.Conclusion
这段不翻译了
英文水平有限仅翻译了部分内容,如有纰漏欢迎各位指正。
文章是我从笔记中整理的,我记笔记比较喜欢截图(就是图省事),不太方便各位复制粘贴了,见谅
希望这篇翻译能帮助你了解RESTful,而不是为了RESTful而RESTful
当然RESTful也有他的不足,以后有机会再写
下面再贴出几家外国公司的API设计供各位参考:
github
Coinbase
Enchant
paypal