背景目前微服务架构盛行。在了解了很多实际的微服务项目后,发现在同时设计业务API接口的时候,有很多种写法。下面总结一下目前项目设计业务对API接口的一些经典误区。Restful架构风格下,API接口设计的经典误区1.查询一个对象接口:GET/app/getImportantApp@GetMapping(path="/getImportantApp")publicRgetImportionApp(@RequestHeader("pid")Stringpid2.查询列表接口:GET/app/list@RequestMapping("/list")publicRlist(StringdeptId)3.保存对象接口:POST/app/save@PostMapping("/save")publicRadd(CmsAppLicationEntityappLication,StringdeptId)4.删除对象接口:POST/app/delete@DeleteMapping("/delete/{applicationId}")publicRdelete(@PathVariable("applicationId")longapplicationId)5.更新对象接口:POST/app/batchUpdate@PostMapping("/batchUpdate")publicRbatchUpdate(@RequestBodyListlist)是感觉很眼熟的代码,是不是写错了?看起来很直观,容易理解。如果是Restful架构风格,上面的五种写法当然是错的,是缺少导致的对Restful的理解建筑风格。微信搜索公众号「狼化」,后台私信回复1024,免费领取SpringCloud、SpringBoot、微信小程序、Java面试、数据结构、算法等全套视频资料。Restful架构风格定义》Restful是一种软件架构风格,设计风格,不是标准,而是提供了一套设计原则和约束。主要用于客户端-服务器交互软件。基于这种风格设计的软件可以更简洁,更有层次,更容易实现缓存等机制由于对Restful架构风格理解不够,一般存在三个有争议的设计误区误区1.请求路径URI是动词,不是名词误区2.URI中间版本号问题的误解URI路径大小写问题的误解1请求路径URI是一个动词,不是名词问题,按照Restful架构风格的理解,每个业务实体代表一个资源和一个名词.比如设计一个产品List界面:错误的写法/getProductList请求路径/getProductList路径出现动词get,th是写法不对。推荐写/products,URL中/addProduct、/deleteProduct、/updateProduct等的写法也是错误的。如果某些动作是HTTP动词无法表达的,则应将动作转化为资源。比如我们获取user下的商品列表,错误的界面设计是:POST/users/1/getProducts或者POST/users/1/getProductList才是正确的写法是把动词getProducts改成名词productsPOST/users/1/products误区二:URI中的版本号对于是否在URI中包含版本号,业界有三种说法。第一种方式是在请求路径中加入版本号,例如:POST/products/v1GET/users/v1POST/orders/v1POST/items/v1这种说法认为在URI中加入版本号可以避免向后兼容,而在此外,通过过期提示、重定向、文档等手段也可以降低用户迁移到新界面的成本。当然,有人赞成在请求路径中添加版本号,也有人反对这种添加版本号的方式。他们认为:增加版本号会使服务接口混乱,经常遇到的情况是一些低版本的API接口调用一些高版本的API接口,导致数据解析错误,这无疑增加了用户迁移的成本。版本的概念与资源无关,因此将版本添加到URI中会使用户感到困惑。还有一种说法是在路径中加入版本号是一种错误的设计方式。老外写的VersioningRESTServices一文指出,你应该在请求的Accept头中指定你的版本号,而不是在请求路径中。例如:例如,对于versions1.0、1.1和2.0ofthefoodattypeasJSONsettheAccept/Content-Typeheaderasfollows:1.0:vnd.example-com.foo+json;version=1.01.1:vnd.example-com.foo+json;version=1.12.0:vnd.example-com.foo+json;version=2.0前端js指定vnd.example-com.foo+json的版本;请求头Accept中的version=1.1。$.ajax({beforeSend:function(req){req.setRequestHeader("Accept","vnd.example-com.foo+json;version=1.1");},type:"GET",url:"http://http://www.example.com/foo/12",success:function(data){/*codeelided*/},dataType:"json"});我个人更倾向于在请求路径中加上版本号,因为我觉得加上版本号是从程序的角度考虑新旧版本的接口移植,尤其是现在流行微服务架构的时候,而且业务粒度很细,接口升级的时候是不是应该保留原来的版本?应该什么时候添加版本号?”如果你开发的restful接口是开放的,不知道是谁调用的,那么这个时候版本号是必须的。以百度地图接口为例,百度发布的restful地图接口在互联网,全国乃至全球的各行各业都可以调用这些接口。如果百度要升级接口,我们该怎么办?如果百度直接升级原来的url,会发生什么??不可预知。程序员:老大,我们的产品当机了!老板:为什么?程序员:百度升级界面了!即使只返回一个字段,也可能导致调用方的原始代码出现问题。毕竟百度不可能全知道人家是怎么解析返回值的。这个时候最好的办法就是加个版本号,保留原来的版本,发布一个新的版本,一切问题都会迎刃而解。老用户不用因为百度升级而更新代码,新用户也能享受到最新的界面,堪称完美。判断是否加版本号的方法:是否清楚知道谁调用了你的接口可以通知,如果是可以不加版本号;restful接口升级时,是否保留原有版本,如果不保留,则不需要添加版本号;当然,添加版本号也是有一定技巧的。版本号应该放在一个功能模块的后面,甚至一个url也应该有自己独立的版本,比如api/user/v2,这样调用或者不会有整套接口升级到v2的错觉。误区三:URI中的路径大小写问题URL中的路径要小写,不能有驼峰式。比如下面这个界面错误的写法是POST/orderItems/v1/1001,推荐的写法是POST/orders/v1/items/1001或者/order-items/v1/1001总结我看过很多基于微服务架构编写的微服务代码。大多数界面似乎都是宁静的风格。但是,仔细辨认后,发现里面有一堆伪restful接口,不是动名词不分,就是Path版本各种乱七八糟。实际场景是restful风格基本停留在口碑上,看起来很高大上的东西只能卖高价。大部分程序员为了赶进度,完成KPI,一直在疯狂编码。附录1API设计风格的基本规则1.使用名词而不是动词不要使用:/getAllUsers/createNewUser/deleteAllUser2.Get方法和查询参数不应涉及状态变化使用PUT、POST和DELETE方法而不是GET方法来改变状态,不要使用GET进行状态更改:3.使用复数名词不要混淆单数名词和复数名词,为了简单起见,对所有资源只使用复数名词。/cars而不是/car/users而不是/user/products而不是/product/settings来部署/setting4。使用子资源表达关系如果一个资源与另一个资源有关系,则使用子资源:GET/cars/711/drivers/returnscar711的所有司机GET/cars/711/drivers/4返回4号司机car7115.使用Httpheader声明序列化格式。客户端和服务器都必须知道通信的格式。格式在HTTP-Header中指定Content-Type定义请求格式Accept定义系列可接受的响应格式6.为集合提供过滤、排序、选择、分页等功能Filtering过滤:使用unique要过滤的查询参数:GET/cars?color=red返回红色carsGET/cars?seats<=2返回少于两个座位的汽车集合Sorting排序:允许对多个字段进行排序GET/cars?sort=-manufactorer,+model这是按生产者的降序和模型的升序返回汽车集合。移动端可以显示其中一些字段,不需要资源的所有字段,让API消费者可以选择字段,这将减少网络流量并提高API可用性。GET/cars?fields=manufacturer,model,id,colorPaging分页,使用limit和offset实现分页,默认limit=20和offset=0;GET/cars?offset=10&limit=5为了将总数发送到客户端,使用自定义HTTP标头:X-Total-Count。链接到下一页或上一页可以在HTTP头的链接中指定,遵循链接规范:链接:;rel="下一个",;rel="最后一个",;rel="first",;rel=“上一个”,7。对API进行版本控制使API版本成为强制性的。不要发布未版本化的API,使用简单的数字,避免小数点如2.5,一般在Url后使用?v/blog/api/v18,使用Http状态码处理如果你的API没有错误处理,错误是很难的,只返回500错误堆栈不一定有用,Http状态码提供了70个错误,我们只需要使用10个左右:200-OK-一切正常201-OK-new资源创建成功204-OK-the资源已成功修改304–NotModified–客户端使用缓存数据400–BadRequest–请求无效,需要额外详细说明如“JSON无效”401–Unauthorized–请求需要用户认证403–Forbidden–the服务器已理解请求,但不允许拒绝服务或访问此类请求。404–Notfound–找不到资源422–UnprocessableEntity–仅在服务器无法处理实体时使用,例如无法格式化的图像,或缺少重要字段。500-InternalServerError-API开发者应该避免这个错误。用详细错误包装错误:{“errors”:[{“userMessage”:“抱歉,therequestedresourcedoesnotexist”,“internalMessage”:“Nocarfoundinthedatabase”“code”:34,“moreinfo”:“http://dev.mwaysolutions.com/blog/api/v1/errors/12345"}]}允许覆盖http方法有些代理只支持POST和GET方法,为了使用这些有限的方法来支持RESTfulAPI,需要一种方法来覆盖http原始方法。使用自定义的HTTP标头X-HTTP-Method-Override覆盖POST方法。附录2HTTP协议描述中常用的动词动词描述GET查询列表或单个对象。使用POST时,一般是提交一个表单或者查询参数比较多的时候。使用PUT更新资源时,使用DELETE删除资源