本文为授权译文。希望查看原文的同学请戳链接:https://hackernoon.com/restful-api-design-step-by-step-guide-2f2c9f9fcdbf
对于我们开发者来说,设计与实现REST API似乎已经成为了我们的日常生活。API现在已经成为了系统间互通的预设方式。AMAZON就是一个有效的使用API进行系统间沟通的最好的例子。在这篇文章中,我将重点讨论如何帮助你设计更好的API并避免一些常见的误区。
杰夫贝索斯的意志-亚麻的成功之路?
可能你已经大概了解了杰夫贝索斯对于亚马逊开发者的要求。如果你还没有听过,以下就是要点:
- 所有的团队今后必须通过服务接口来开放自己的数据和服务功能。
- 团队间只能通过这些接口进行通信。
- 其他所有的方式都不被允许:不可以直链,不可以直接去读取其他队伍的数据源,不能通过共享内存通信,不可以通过服务后门通信。总之,只能通过网络接口进行服务间的通信。
- 任何实现接口的技术都是被允许的:HTTP,Corba,Pubsub,自定义协议。贝索斯不在乎具体的实现。
- 所有的接口都需要被设计成可暴露型,不允许任何特例。也就是说,所有的团队都必须计划将自己的服务接口设计成可以被暴露给狂野的外部世界的形式。
- 任何人不遵守以上协议的,就滚蛋吧。
以上的要求现在看来正是亚马逊成功的关键。亚马逊在内部开发出可扩展的服务,成熟后就将这些服务暴露给外界使用。于是就有了我们所熟悉的强大的AWS。
RESTful API的设计原则
好吧,现在我们就开始了解一些我们设计RESTful API时需要遵守的一些原则。
能简单就简单 Keep It Simple
我们需要确保API的URL是简单的。比如说,如果我们要设计一个关于产品的API,他应该是这样的:
/products
/products/12345
第一个API用来返回所有的产品,第二个则用来返回特定的产品。
使用名词而不是动词
很多开发者会犯这个错误。他们大概忘了我们已经后HTTP的Methods来帮助我们表达动词的部分。不如,一个用来得到所有产品的的API应该是:
/products
而不是
/getAllProducts
使用正确的HTTP方法
RESTful API有不同的方法来标示这个API操作的类型:
- GET-要从服务中得到某个或者一些数据
- POST-要在服务中创建某个或者一些数据
- PUT/PATCH-要更新服务中的某些已有的数据
- DELETE-要删除一些服务中已有的数据
我们需要确保我们在对应的API上使用正确的HTTP方法。
使用复数
这个观点有一些争议。有些人喜欢在设计URL时使用复数而有些人认为保持单数更合适。比如
/products
/product
我个人喜欢使用复数。原因呢就是这样可以避免迷惑使用者这个API到底是要返回单个数据还是一个数据的集合。同时这样的设计也可以避免需要在Base URL叠放额外的参数,比如:/product/all
有些人可能不喜欢这个建议。那我的意见是至少你要在一个Project中保持命名的统一。
使用参数
有时候我们需要设计更复杂的API。这些API不止需要传入id,可能还要传入更复杂的参数。这时,我们就应该使用参数来设计API,比如:
- /products?name='ABC' 就要比 /getProductsByName 要更好
- /products?type='xyz' 就要比 /getProductsByType 要更好
这样你就可以避免使用很长的URL来表达自己的意图。设计变得更简洁。
使用合适的HTTP状态码
HTTP为我们提供了丰富的状态返回码。然而令人遗憾的是,我们大部分人只使用了其中的两个-200和500!这肯定不是一个很好的实践!一下就一些你可以马上实用的HTTP状态码:
- 200 OK-这是HTTP中最常用的状态码。用来标示所请求的操作成功了。
- 201 CREATED-这个状态码标示你使用POST操作所创建的资源创建成功了。
- 202 ACCEPTED-这个标示服务器获得并认可了你发送请求。
- 400 BAD REQUEST-这个则用来标示用户输入的数据有误。
- 401 UNAUTHRORIZED/403 FORBINDDEN-这两个状态码用来告诉用户没有权限或者没有被授权进行所请求的操作。
- 404 NOT FOUND-这个状态码用来告诉用户你想要寻找的资源并不存在。
- 500 INTERNAL SERVER ERROR-你永远不应该显示的抛出这个异常。只有在系统异常出现时由系统自动抛出。
- 502 BAD GATEWAY-如果从上游的服务中收到了任何异常或者不正确的响应,这是合适的选择。
使用版本
使用版本对于API来说是很重要的!不同的企业有不同使用版本的习惯。有些使用日期来表示版本。有些则使用查询参数来表示版本。我个人更喜欢把版本放到URL的前缀上。比如:
/v1/products
/v2/products
而且我会尽量避免使用小版本号/v1.2/products/。因为这样会让人觉得你的API会频繁的变化。同时,(.)这个点并不是能够很快的在URL中被看到。所以,还是越简单越好吧!
同时,保持版本的向前兼容是很重要的实践。这样即使你改变了API版本,你的客户也有足够的时间来跟进你所进行的变化。
使用分页(Pagination)
当一个API可能会返回巨量数据的时候,使用分页成为了必须。否则用户可能会使服务器崩溃。
We need to always keep in mind that the API design should be full proof and fool proof.
我推荐使用limit和offset这两个参数。比如,/products?limit=25&offset=50 同时你也要考虑设置一个默认的limit和offset。
支持的格式
选择合适的API响应信息的格式是很重要的。大多数现代应用都会使用JSON。你也应该使用JSON,除非你有一些旧时的需求要求你使用XML响应。
回复合适的错误代码
一个很好的实践就是保持一个服务错误信息的集合并加上合适的ID。比如,如果你使用过FACEBOOK的graph API,当产生错误时,它会给你返回:
{
"error": {
"message": "(#803) Some of the aliases you requested do not exist: products",
"type": "OAuthException",
"code": 803,
"fbtrace_id": "FOXX2AhLh80"
}
}
我也见过有些错误信息还会告诉用户如何应对这个错误。这也是一个很好的实践。
使用OPEN API SPECIFICATIONS
如果你也像我一样希望所有的团队都遵守统一的规则,你可以使用OPEN API Specification。Open API允许我们在设计好API后更加便捷的分享给客户或者其他团队。
总结
显而易见的,如果你想要更好的和客户或者其他团队沟通,API绝对是正确的方式。但如果API没有被很好的设计,反而会徒增别人(或者也有你自己?)的困惑。所以,请在设计阶段放入更多的心思。剩下的只不过就是实现而已了!
感谢您的阅读
如果你对设计API有更好的意见和建议,请在评论区分享出来吧!欢迎任何的反馈和纠错!谢谢!