今年,边肖在一家移动互联网公司工作,设计和开发应用程序的后端界面。最近群里做了一个很大的改造,就是界面完全按照restful规范设计重写。这样做的目的首先是为了降低与前端app同事的沟通成本,其次restful已经成为最流行的界面设计规范,比如instagram和facebooke等都在使用。下面是instagram提供的在线界面文档截图。
下图是我们的界面文档截图:
本文仅解释restful设计理论。如果你真的决定使用它,你可以在任何其他问题上留言,比如用什么工具来设计api文档,等等。主题开始出现:
目前网上充斥着关于如何设计RESTful API的文章,却没有“通用”的设计标准:如何认证?API格式是什么?是否应该给自己的API添加版本信息?当你开始写一个应用的时候,尤其是后端模型部分已经写好的时候,你就要设计和实现你的应用的公共API部分。因为一旦发布,向外界发布的API将很难改变。
在为SupportedFu设计API的时候,我尝试从实用的角度来解决上面的问题。我希望我能设计出一个易用、易部署、足够灵活的API,于是本文就诞生了。
原料药设计的基本要求
网上很多关于API设计的观点都是“学术性”的。他们可能有更多的理论基础,但有时会偏离现实世界。所以本文的目标是从实用的角度给出当前网络应用API设计的最佳实践。如果不合适,我就不按标准来了。当然,作为设计的基础,应该遵守几个必要的原则:
合理时遵守标准。
API应该是程序员友好的,容易在浏览器地址栏输入。
API应该简单、直观、易用、优雅。
API应该足够灵活,能够支持上层ui。
API设计权衡以上原则。
需要强调的是,API是程序员的UI。像其他UIS一样,你必须仔细考虑它的用户体验!
使用RESTful网址和动作。
虽然我前面说过没有通用的API设计标准。但是有一个普遍公认和遵守的:RESTfu设计原则。它是由罗伊·费尔德丁提出的。REST的核心原则是把你的API拆分成逻辑资源。这些资源通过http操作。
那么我应该如何拆分这些资源呢?
显然,从API用户的角度来看,“资源”应该是一个名词。即使你的内部数据模型和资源有很好的对应关系,在设计API的时候还是不需要一一暴露。这里的关键是隐藏内部资源,暴露必要的外部资源。
在SupportFu中,资源是票证、用户和组。
一旦定义了要公开的资源,您就可以定义资源上允许的操作以及这些操作和您的应用编程接口之间的对应关系:
获取/门票#获取门票列表
获取/门票/12 #查看特定门票
张贴/票证#创建新票证
用PUT/tickes/12 #更新票证12。
删除/门票/12 #删除ticekt 12
由此可见,使用REST的好处是可以充分利用http的力量,实现资源的凝乳功能。而这里你只需要一个端点:/tickets,没有其他命名规则和url规则,酷!
这个端点的单数和复数
可以遵循的一个规则是:虽然用复数来描述资源实例看起来很笨拙,但是统一所有端点并使用复数来使您的URL更规则。这使得API用户更容易理解,开发人员更容易实现。
怎么处理联想?还有关于如何处理资源间REST管理原则的相关描述:
获取/票证/12/消息-检索票证#12的消息列表
获取/票证/12/消息/5-检索票证#12的消息#5
发布/票证/12/消息-在票证#12中创建新消息
PUT /tickets/12/messages/5-更新#12票证的消息#5
补丁/票证/12/消息/5-部分更新票证#12的消息#5
删除/票证/12/消息/5-删除票证#12的消息#5
如果关联独立于资源,我们可以在资源的输出表示中保存相应资源的端点。然后API用户可以通过点击链接找到相关资源。如果联想和资源密切相关。资源的输出意味着相应的资源信息要直接保存。
不符合凝乳的操作
以下是这个令人困惑的问题的一些解决方案:
重建你的行动。当您的行为不需要参数时,您可以将活动映射到激活的资源。
作为子资源对待。例如,在github上,将星星添加到一个gist:PUT/gist/:id/star,并取消星星:DELETE/gist/:id/star。
有时候动作对应某个资源并不难,比如搜索。那我们开始吧。我觉得API用户对URL/搜索没什么意见。只要注意在文档里写清楚就行了。
始终使用SSL
无一例外,始终使用SSL。您的应用程序不知道谁以及在什么情况下会被访问。有些安全,有些不安全。使用SSL可以降低身份验证的成本:您只需要一个简单的令牌来进行身份验证,而不是每次都要求用户对每个请求进行签名。
值得注意的是:不要让非SSL url访问被重定向到SSL url。
文件
文档和API本身一样重要。文档应该易于查找和打开。文档应该有显示请求和输出的例子:要么通过点击链接,要么通过curl。如果有更新,文档要及时更新。文档中应该有何时丢弃API的时间表和细节。使用邮件列表或博客记录是个好主意。
版本
在API中添加版本信息可以有效防止用户访问更新后的API,也可以在不同的主要版本之间进行平滑过渡。关于是否将版本信息放在url或请求头中存在争议:。学者说它应该放在标题中,但是如果它放在网址中,我们可以跨版本访问资源。。。
strip使用的方法很好:它的url包含了主要的版本信息,同时它要求前两面都有子版本信息。这样,url在子版本更改过程中是稳定的。改变有时候是不可避免的,关键是如何管理。完整的文档和合理的日程安排将使API用户更容易使用它。
过滤、排序和搜索结果:
url要尽量短,与结果过滤、排序、搜索相关的功能要通过参数实现。
过滤:为所有提供过滤功能的接口提供统一的参数。例如,您希望限制get/ticketsstate的返回结果:只返回那些处于打开状态的票据–get/ticketsstate = open,其中状态是筛选参数。
排序:和过滤一样,一个好的排序参数应该能够描述排序规则,但不能与业务相关。复杂的排序规则应该通过组合来实现:
GET /ticketssort=-priority-按优先级降序检索票证列表
GET /ticketssort=-priority,created_at-按优先级降序检索票证列表。在特定的优先级内,会先订购旧票
在这里的第二个查询中,排序规则中有多个规则,它们以逗号间隔组合在一起。
搜索:有时候单纯的排序是不够的。我们可以使用搜索技术来实现它。
GET/ticket sq = return & amp;状态=打开& ampsort=-priority,created_at-检索提及“返回”一词的最高优先级开放票证
对于常用的搜索查询,我们可以为它们创建别名,这样会让API更优雅。例如:
get/ticket sq =最近关闭->。get/tickets/最近关闭。
限制应用编程接口返回值的域
有时候API用户并不需要所有的结果,在做水平限制的时候也应该可以垂直限制。而且这个功能可以有效提高网络带宽利用率和速度。您可以使用字段查询参数来限制返回的字段。例如:
GET /ticketsfields=id,subject,customer_name,updated _ at & amp状态=打开& ampsort=-updated_at
更新和创建操作应该返回资源
PUT、POST和PATCH操作在操作资源时经常会有一些副作用,比如创建_ at和更新_ at时间戳。为了防止用户多次调用API,我们应该返回更新的资源.例如,在POST操作之后,返回201创建的状态代码,并且包括指向新资源的url作为返回标题。
需要“HATEOAS”吗
在互联网上,对于是否允许用户创建新的网址存在很大的分歧。为此,REST制定了HATEOAS来描述在与端点交互时,行为应该在资源的元数据返回值中定义。
只提供json作为返回格式
现在我们来比较一下XML和json。XML冗长难读,不适合各种编程语言解析。当然,XML有可扩展性的优势,但是如果只用它序列化内部资源,它的可扩展性优势就发挥不出来了。很多应用已经抛弃了XML,我不想再浪费时间了。在谷歌上给出趋势图:
当然,如果您的大多数用户是企业用户,您可能需要支持XML。如果是这样,你还有另外一个问题:你的http请求中的媒体类型应该与接受头同步还是与url同步?为了浏览器的可探索性,它应该在url中。在这种情况下,最好的方法是使用的后缀。xml或。json。
命名方法?
是snake命令还是驼峰命名?如果使用json,最好的办法是遵循JAVA命名方法——也就是camel命名方法。如果你正在用多种语言编写一个库,最好使用java中的camel、c#、python中的snake和ruby,这些语言都推荐这样做。
个人观点:我一直觉得蛇指挥比较好,但是没有理论依据。有人说蛇形命名可以读的更快,达到20%,你也不知道是真是假
默认情况下,使用漂亮的打印格式和g
仅仅用空网格返回结果,从浏览器上看总是感觉很恶心。当然,您可以在url上提供参数来控制“漂亮打印”的使用,但是默认情况下打开这个选项更友好。额外的传输损耗不会太大。反之,如果忘记使用g,传输效率会大大降低,损耗也会大大增加。想象一个用户在调试,那么默认输出是可读的——而不是把结果复制到其他软件进行格式化——想起来很爽吧?
以下是一个例子:
$ curl https://API.github.com/users/veesahni & gt;with-空格. txt $ ruby-r JSON-e ' puts JSON JSON . parse' & lt;with-whitespace.txt >。不带-空格. txt$ g -c带-空格. & gtwith-空格. txt.gz$ g -c不带-空格. & gtwithout-whitespace.txt.gz
输出如下:
不带-空格. txt- 1252字节
with-空格. txt- 1369字节
不带-空格. txt.gz- 496字节
with-空格. txt.gz- 509字节
在上面的例子中,额外的空网格使结果大小增加了8.5%,但只增加了2.6%。据说推特的流媒体API传输量减少了80%。
仅在需要时使用“信封”
许多应用编程接口返回如下结果:
一个
2
三
四
五
六
{
"数据":{
:123,
“姓名”:“约翰”
}
}
原因很简单:这样可以轻松扩展返回结果,可以添加一些分页信息,数据的一些元信息等。——这对于不容易访问返回头的API用户来说确实很有用,但是随着“标准”的发展,我个人建议不要这样做。
什么时候用信封?
有两种情况应该使用信封。如果API消费者不能访问返回头,或者如果API需要支持跨域请求。
jsonp请求在请求的url中包含一个回调函数参数。如果给定了这个参数,那么API应该返回200,并将真实状态代码放入返回值中,例如:
一个
2
三
四
五
六
七
回调函数
同样,为了支持不能通过方法返回头的API消费者,可以允许诸如envelope=true的参数。
使用json作为发布、放置和修补的输入
如果你同意我上面说的,那么你应该决定使用json作为所有API的输出格式,那么接下来我们就要考虑API的输入数据格式了。
很多API使用url编码格式:就像url查询参数的格式:简单的键值对。这种方法简单有效,但也有其自身的问题:没有数据类型的概念。这就使得程序不得不根据字符串来解析Boolean和integer,而且没有层次结构——虽然有一些关于层次结构信息的约定,但是和本身支持层次结构的json相比并不是很有用。
当然,如果API本身比较简单的话,url格式的输入也没什么问题。但是对于复杂的API,应该用json。或者干脆统一使用json。
注意使用json传输时,需要添加:内容-类型:application/JSON。否则将引发415异常。
标页数
寻呼数据可以放在“信封”里,但是随着标准的提高,现在我建议把寻呼信息放在链路头:http://tools.ietf.org/html/rfc5988#page-6.
使用链接头的API应该返回一系列组装好的URL,而不是让用户重新拼写。这在基于游标的分页中尤其重要。例如,在下面,来自github的文档
一个
2
链接:& lthttps://api.github.com/user/repos?·佩奇= 3 & ampper_page=100>。;rel="next ",
& lthttps://api.github.com/user/repos?·佩奇= 50 & ampper_page=100>。;rel="last "
自动加载相关资源
在很多情况下,自动加载相关资源是非常有用的,可以大大提高效率。但这是。为此,我们可以在url中添加一个参数:嵌入。嵌入可以是逗号分隔的字符串,例如:
一个
GET/ticket/12 embed = customer . name,assigned_user
对应的API返回值如下:
一个
2
三
四
五
六
七
八
九
10
11
12
{
:12、
“主题”:“我有个问题!”,
“总结”:“嗨,...”,
“客户”:{
“姓名”:“鲍勃”
},
assigned_user: {
:42,
“名字”:“吉姆”,
}
}
值得提醒的是,这个功能有时候比较复杂,可能会导致。
覆盖HTTP方法
有些客户端只能发送简单的GET和POST请求。为了处理它们,我们可以重写HTTP请求。这里没有标准,但是一个常见的方法是接受X-HTTP-Method-Override请求头。
限速
为了避免请求泛滥,为应用编程接口设置速度限制很重要。所以引入了HTTP状态码。添加速度设置后,应提示用户。怎么提示没有说明,但是流行的方法是使用HTTP的返回头。
以下是一些必需的返回标题:
x-速率限制-限制:当前时间段内允许的并发请求数
X-速率限制-剩余:当前时间段内保留的请求数。
限速重置:当前时间段内剩余的秒数
为什么使用当前时间段的剩余秒数而不是时间戳?
时间戳保存了很多信息,但也包含了很多不必要的信息。用户只需要知道只剩下几秒钟就可以再次发送请求了。
有些API使用UNIX格式的时间戳,我建议不要这样做。为什么?HTTP已指定使用时间格式
认证
restful API是无状态的,这意味着用户请求的认证与cookie和会话无关,每个请求都应该包含认证证书。
通过使用ssl,我们不必每次都提供用户名和密码:我们可以向用户返回随机生成的令牌。这可以极大地方便使用浏览器访问API的用户。这种方法适用于用户通过用户名-密码验证并首先获取令牌,然后将返回的令牌复制到将来的请求中。如果不方便,OAuth 2可以用于令牌的安全传输。
支持jsonp的API需要额外的身份验证方法,因为jsonp请求无法发送普通凭据。在这种情况下,您可以向查询url添加一个参数:access_token。注意使用url参数的问题:目前大多数网络服务器都会将查询参数保存在服务器日志中,这可能会成为很大的安全隐患。
注意,传输令牌的方式只有三种,实际传输的令牌可能是相同的。
高速缓存
HTTP提供了自己的缓存框架。您需要做的是在返回时添加一些返回头信息,在接受输入时添加输入验证。有两种基本方法:
ETag:生成请求时,在HTTP头中添加ETag,其中包含请求的校验和和哈希值。当输入改变时,该值也应该改变。如果输入的HTTP请求包含一个IF-NONE-MATCH头和一个ETag值,那么API应该返回304未修改状态码,而不是常规输出结果。
最后修改:与etag相同,只添加一个时间戳。返回头中的Last-Modified:包含时间戳,与IF-Modified-after一致。HTTP规范中有三种日期格式,应该由服务器处理。
错误处理
正如html错误页面可以显示错误消息一样,API也应该能够返回可读的错误消息——它应该与通用资源格式一致。API应该总是返回相应的状态代码,以反映服务器或请求的状态。API的错误代码可以分为两部分,400系列和500系列。400系列表示客户端错误,例如错误的请求格式。500系列表示服务器错误。API至少应该将所有400系列错误作为json返回。如果可能,500系列错误也应该如此。json格式的错误应该包含以下信息:有用的错误消息、唯一的错误代码以及任何可能的详细错误描述。如下:
一个
2
三
四
五
{
:1234,
“消息”:“发生了不好的事:-(”,
“关于错误的更多细节”
}
输入的put、post和patch的验证还应返回相应的错误信息,如:
一个
2
三
四
五
六
七
八
九
10
11
12
13
14
15
16
{
:1024,
"消息":"验证失败",
"错误":
}
http状态代码
一个
2
三
四
五
六
七
八
九
10
11
12
200 ok-状态成功返回,对应于GET、PUT、PATCH、DELETE。
201创建-成功创建。
304未修改-HTTP缓存有效。
400错误请求-请求格式错误。
401未经授权-未经授权。
403禁止-验证成功,但用户没有权限。
404未找到-请求的资源不存在
不允许405方法-不允许此http方法。
410没了——这个网址对应的资源现在不可用。
415不支持的媒体类型-错误的请求类型。
422不可处理实体-检查错误时使用。
要求太多了-要求太多了。
1.《restful接口 Restful 接口设计最佳事件》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。
2.《restful接口 Restful 接口设计最佳事件》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。
3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/yule/1712874.html