Java基础、中级、高级、架构面试资料

RESTful 的 7 个最佳实践

业余杂谈 herman 1995浏览
公告:“业余草”微信公众号提供免费CSDN下载服务(只下Java资源),关注业余草微信公众号,添加作者微信:xttblog2,发送下载链接帮助你免费下载!
本博客日IP超过2000,PV 3000 左右,急需赞助商。
极客时间所有课程通过我的二维码购买后返现24元微信红包,请加博主新的微信号:xttblog2,之前的微信号好友位已满,备注:返现
受密码保护的文章请关注“业余草”公众号,回复关键字“0”获得密码
所有面试题(java、前端、数据库、springboot等)一网打尽,请关注文末小程序
视频教程免费领
腾讯云】1核2G5M轻量应用服务器50元首年,高性价比,助您轻松上云

RESTful 是目前最流行的 API 设计规范,是一种网络应用程序的设计风格和开发方式,基于 HTTP,可以使用 XML 格式定义或 JSON 格式定义。

REST 的全称叫:表现层状态转换(英语:Representational State Transfer,缩写:REST)是 Roy Thomas Fielding 博士于 2000 年在他的博士论文中提出来的一种万维网软件架构风格,目的是便于不同软件/程序在网络(例如互联网)中互相传递信息。

很多人往往会理解错 RESTful,本文列举了 RESTful 的 7 个最佳实践,希望能加深大家对 RESTful 的理解!

版本

相信不少人在面试中都被问到过,RESTful 在遇到版本问题时是如何设计的。这里我们可以借鉴 Github 的做法。

如 github 开放平台 https://developer.github.com/v3/,就是将版本放在 url,简洁明了,这个只有用了才知道,一般的项目加版本 v1,v2,v3。。。

也有的项目会将版本号放在 header 里面,但是不如放在 url 直接了当。

除了 Github,Google APIs 和 Twitter APIs 在 URL 中加入了版本。需要注意的是在 URL 中带有版本信息,并不是使用错误。这是一种正确的合法的,符合 REST 各种约束的使用方法。

参数命名规范

query parameter 可以采用驼峰命名法,也可以采用下划线命名的方式,推荐采用下划线命名的方式,据说后者比前者的识别度要高。当然这也不是绝对的,具体因团队规范而异吧。

https://example.com/api/users/today_login 获取今天登陆的用户
https://example.com/api/users/today_login&sort=login_desc 获取今天登陆的用户、登陆时间降序排列

url 命名规范

API 命名应该采用约定俗成的方式,保持简洁明了。在 RESTful 架构中,每个 url 代表一种资源所以 url 中不能有动词,只能有名词,并且名词中也应该使用复数。实现者应使用相应的 Http 动词 GET、POST、PUT、PATCH、DELETE、HEAD 来操作这些资源即可。

不规范的的 url,冗余没有意义,形式不固定,不同的开发者还需要了解文档才能调用。

https://example.com/api/getallUsers GET 获取所有用户
https://example.com/api/getuser/1 GET 获取标识为1用户信息
https://example.com/api/user/delete/1 GET/POST 删除标识为1用户信息
https://example.com/api/updateUser/1 POST 更新标识为1用户信息
https://example.com/api/User/add POST 添加新的用户

规范后的 RESTful 风格的 url,形式固定,可读性强,根据 users 名词和 http 动词就可以操作这些资源。

https://example.com/api/users GET 获取所有用户信息
https://example.com/api/users/1 GET 获取标识为1用户信息
https://example.com/api/users/1 DELETE 删除标识为1用户信息
https://example.com/api/users/1 Patch 更新标识为1用户部分信息,包含在body中
https://example.com/api/users POST 添加新的用户

统一返回数据格式

对于合法的请求应该统一返回数据格式,这里演示的是 json。

  • code——包含一个整数类型的HTTP响应状态码。
  • status——包含文本:”success”,”fail”或”error”。HTTP状态响应码在500-599之间为”fail”,在400-499之间为”error”,其它均为”success”(例如:响应状态码为1XX、2XX和3XX)。这个根据实际情况其实是可要可不要的。
  • message——当状态值为”fail”和”error”时有效,用于显示错误信息。参照国际化(il8n)标准,它可以包含信息号或者编码,可以只包含其中一个,或者同时包含并用分隔符隔开。
  • data——包含响应的body。当状态值为”fail”或”error”时,data仅包含错误原因或异常名称、或者null也是可以的

返回成功的响应 json 格式

{
  "code": 200,
  "message": "success",
  "data": {
    "userName": "123456",
    "age": 16,
    "address": "beijing"
  }
}

返回失败的响应 json 格式。

{
  "code": 401,
  "message": "error  message",
  "data": null
}

下面这个 ApiResult 的泛型类是在项目中用到的,拓展性强,使用方便。返回值使用统一的 ApiResult 或 ApiResult 错误返回 使用 ApiResult.Error 进行返回;成功返回,要求使用 ApiResult.Ok 进行返回。

http 状态码

在之前开发的 xamarin android 博客园客户端的时候,patch、delete、post 操作时 body 响应里面没有任何信息,仅仅只有 http status code。HTTP 状态码本身就有足够的含义,根据 http status code 就可以知道删除、添加、修改等是否成功。(ps:有点linux设计的味道哦,没有返回消息就是最好的消息,表示已经成功了)服务段向用户返回这些状态码并不是一个强制性的约束。简单点说你可以指定这些状态,但是不是强制的。常用 HTTP 状态码对照表 HTTP 状态码也是有规律的。

  • 1** 请求未成功
  • 2** 请求成功、表示成功处理了请求的状态代码。
  • 3** 请求被重定向、表示要完成请求,需要进一步操作。通常,这些状态代码用来重定向。
  • 4** 请求错误这些状态代码表示请求可能出错,妨碍了服务器的处理。
  • 5**(服务器错误)这些状态代码表示服务器在尝试处理请求时发生内部错误。这些错误可能是服务器本身的错误,而不是请求出错。

合理使用query parameter

在请求数据时,客户端经常会对数据进行过滤和分页等要求,而这些参数推荐采用HTTP Query Parameter的方式实现。

比如设计一个最近登陆的所有用户
https://example.com/api/users?recently_login_day=3
搜索用户,并按照注册时间降序
https://example.com/api/users?recently_login_day=3
搜索用户,并按照注册时间升序、活跃度降序
https://example.com/api/users?q=key&sort=create_title_asc,liveness_desc
关于分页,看看博客园开放平台分页获取精华区博文列表
https://api.cnblogs.com/api/blogposts/@picked?pageIndex={pageIndex}&pageSize={pageSize}
返回示例:
[ 
  {
    “Id”: 1,
    “Title”: “sample string 2”,
    “Url”: “sample string 3”,
    “Description”: “sample string 4”,
    “Author”: “sample string 5”,
    “BlogApp”: “sample string 6”,
    “Avatar”: “sample string 7”,
    “PostDate”: “2017-06-25T20:13:38.892135+08:00”,
    “ViewCount”: 9,
    “CommentCount”: 10,
    “DiggCount”: 11
  },
  {
    “Id”: 1,
    “Title”: “sample string 2”,
    “Url”: “sample string 3”,
    “Description”: “sample string 4”,
    “Author”: “sample string 5”,
    “BlogApp”: “sample string 6”,
    “Avatar”: “sample string 7”,
    “PostDate”: “2017-06-25T20:13:38.892135+08:00”,
    “ViewCount”: 9,
    “CommentCount”: 10,
    “DiggCount”: 11
  }
]

多表、多参数连接查询如何设计URL

这是一个比较头痛的问题,在做单个实体的查询比较容易和规范操作,但是在实际的API并不是这么简单而已,这其中常常会设计到多表连接、多条件筛选、排序等。比如我想查询一个获取在6月份的订单中大于500元的且用户地址是北京,用户年龄在22岁到40岁、购买金额降序排列的订单列表。

https://example.com/api/orders?order_month=6&order_amount_greater=500&address_city=北京&sort=order_amount_desc&age_min=22&age_max=40

从这个 URL 上看,参数众多、调用起来还得一个一个仔细对着,而且API本身非常不容易维护,命名看起来不是很容易,不能太长,也不能太随意。

在.net WebAPI 总我们可以使用属性路由,属性路由就是讲路由附加到特定的控制器或操作方法上装饰 Controll 及其使用[Route]属性定义路由的方法称为属性路由。

这种好处就是可以精准地控制URL,而不是基于约定的路由,简直就是为这种多表查询量身定制似的的。从webapi 2开发,现在是RESTful API开发中最推荐的路由类型。我们可以在Controll中标记 Route。

[Route(“api/orders/{address}/{month}”)]

Action中的查询参数就只有金额、排序、年龄。减少了查询参数、API的可读性和可维护行增强了。

https://example.com/api/orders/beijing/6?order_amount_greater=500&sort=order_amount_desc&age_min=22&age_max=40

这种属性路由比如在博客园开放的 API 也有这方面的应用,如获取个人博客随笔列表。

请求方式:GET
请求地址:https://api.cnblogs.com/api/blogs/{blogApp}/posts?pageIndex={pageIndex}
(ps:blogApp:博客名)

以上,7 种最佳实践希望能对大家有所帮助!

业余草公众号

最后,欢迎关注我的个人微信公众号:业余草(yyucao)!可加作者微信号:xttblog2。备注:“1”,添加博主微信拉你进微信群。备注错误不会同意好友申请。再次感谢您的关注!后续有精彩内容会第一时间发给您!原创文章投稿请发送至532009913@qq.com邮箱。商务合作也可添加作者微信进行联系!

本文原文出处:业余草: » RESTful 的 7 个最佳实践