RESTful API设计指南(5)——如何实现RESTful API(中)

引言

在上文 RESTful API设计指南(4)——如何实现RESTful API(上) 中,我们介绍了实现 RESTful API 的关键是正确的使用 HTTP 协议,本文我们将结合2个案例来进行入门:

  • 登录 API 的设计与实现
  • 一个部门管理 CURD 功能 API 的设计与实现

每个例子都包含2个部分:

  • RESTful API 设计
  • go 代码实现

下面,让我们先从登录 API 的设计开始!

项目背景

现在需要开发一套类企业微信的内网沟通工具,后端采用微服务架构,你负责其中 console 端的开发,主要提供组织架构、用户和权限角色等管理功能,现在你打算使用 RESTful API 风格实现和前端交互。

按照以往成功的项目经验,你打算先把 API 设计好,这样前后端就可以一起开发,最后联调上线。

让我们先从登录API的设计开始,然后再来设计部门管理的API。

登录 API 的设计与实现

API 分析与设计

这个系统我们使用用户名和密码来进行登录验证,更复杂的登录方式(如短信和第三方社交软件快捷登录认证)并不在我们的讨论范畴。

前端界面上给用户提供了账户输入框和密码输入框,所以我们的 API 至少需要2个参数:

  • user_name: 代表用户输入的账户
  • user_pwd:代表用户输入的密码(注意,主流做法是加盐hash,不传输明文)

当后端校验通过后,登录 API 需要发放一个有时效的令牌(token)返回用户(前端界面),以能通过后续部门管理 API 的鉴权操作。

按照上文的4个步骤,我们来逐步确定这个 RESTful API。

  • 设计好 URL 和 HTTP 主体
  • 正确选择 HTTP 方法
  • 充分利用 HTTP 报头
  • 正确选择 HTTP 状态码

前3个步骤是为了确定 API 的请求部分,第4个步骤是为了确定 API 的响应部分。最终我们会得到如下的API:
在这里插入图片描述
图1:登录 RESTful API 文档示例

下面,让我们按照上述4个步骤,来设计我们的第一个 RESTful API 吧!

1)设计好 URL 和 HTTP 主体

在前面的文章 RESTful API 设计指南(3)——为什么要用(下) 中,我们对登录 URL 和 使用何种 HTTP 方法进行了解析,有时候 RESTful API 不能很好的映射到资源对象上,需要我们打破规范,站在使用者的角度进行思考。

所以登录 URL,我们使用了“auth/login”,login 本身是一个动词,并不符合 RESTful API 对资源必须是名词的定义,但是见名知意。当然,我们也可以询问 Chat GPT 等 AI 大模型,寻找主流 RESTful API 命名设计,选一个你认为合适的。

URL 设计完成后,我们来设计 HTTP 主体部分,主要分成:

  • 请求体:客户端发给服务器的数据
  • 响应体:服务器返回的数据

消息体可以是各种格式,字符串、xml、json、表单或者二进制等等,而 RESTful API 中都使用 json 格式,所以,我们最终的请求为:

{
   
   
 "user_name": "admin",
 "user_pwd": "111111"
}

响应为:

  • 成功,则返回的状态码为 200 OK
{
   
   
 "id": 1024,
 "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9"
}
  • 异常,则返回的状态码分2大类,如果是客户端参数等问题导致的异常,返回 4xx 错误,如果是服务端内部异常,返回 5xx 错误,但不管是那种错误,返回的消息体都是一样的
{
   
   
 "code": 40000001,
 "casue": "hello-restapi.go:12 user_name 参数为空",
 "message": "参数不能为空"
}

也就是 “图1:登录 RESTful API 文档示例” 中(3)(4)(5)(6)的部分。在异常的字段中,code 是给机器使用的,用以判断具体的错误原因给出下一步动作,casue 是给排查问题使用,message 是显示给用户的信息,可以根据业务灵活调整,后续有机会再深入介绍。

2)正确选择 HTTP 方法

登录会产生日志,可能会踢人下线,可能会产生上线通知等等,所以从接口幂等角度看,登录一次和登录多次的行为是不一样的,故我们需要使用不幂等的 HTTP 方法,GET、PUT 和 DELETE 都是幂等的,所以我们只剩下 POST 可以选择。

也就是 “图1:登录 RESTful API 文档示例” 中 (1)的部分。
在这里插入图片描述

更多关于各种 HTTP 方法的对比和幂等性在前文有详细介绍:

3)充分利用 HTTP 报头

当我们希望知道客户使用的环境信息时,我们可以追加 User-Agent 这个头,在浏览器环境中,这个 HTTP 报头会被自动加上,以下是一个示例:

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36

当我们认证完成返回 token 给客户端时,后续的请求都需要携带 token,此时我们可以利用 HTTP 协议中的 “Authorization” 头来携带我们的令牌,这个部分在案例2中会详细介绍。

如果没有适合的 HTTP 报头怎么办?我们可以自定义报头,其通常以 “X-” 开头,比如我们希望对每一个请求都分配一个唯一ID,则可以使用如下报头:

X-Request-ID:cc1f2c7d-0f29-4c3b-a2e5-7e3c8e1a9d35

4)正确选择 HTTP 状态码

至此,我们 RESTful API 的定义就完成了,后续仅需要根据 API 处理结果,正确的返回 HTTP 状态码即可。

那么,登录的场景,应该返回什么状态码?

  • 200 OK:成功时返回,Body 中携带你希望传递的数据,比如用户ID,token 令牌等
  • 400 Bad Request
    • 表示客户端发送的请求存在语法错误或无法理解的请求,包括由于用户提供的数据不符合服务器的要求而导致的错误
    • 如:用户名或密码为空、密码位数不足、用户名过短或者不是指定格式等等
    • 400 错误码通常是可重试的,当客户端更换参数后,下一次请求就有可能成功
  • 403 Forbidden
    • 表示服务器理解请求,但拒绝执行它,通常是由于缺少权限而导致的
    • 如:用户名和密码不匹配或不正确、用户被禁止登录等。因为此时客户端参数都是正常的,返回 400 并不合适,故使用 403 状态码。表明已对用户进行身份验证,但是由于提供的凭据无效,因此服务器拒绝了请求。这表明请求是有效的,但服务器拒绝响应。
  • 404 Not Found
    • 当客户端请求的资源在服务器上未被找到时返回
    • 如:用户不存在,但是出于安全考虑,更建议 403 模糊返回用户名和密码不匹配,防止撞库等检测系统用户名的情况
  • 409 Conflict
    • 表示服务器在尝试处理请求时发生冲突的情况,通常用于表示由于请求可能导致冲突而无法处理的情况
    • 如:用户重复登录。假设一个用户已经登录,但是他们尝试使用相同的凭据再次登录,而系统不允许一个用户同时有多个活动会话。在这种情况下,服务器可以返回 409 状态码来表示冲突,因为用户已经有一个有效的会话,再次登录会导致冲突
  • 500 Internal Server Error
    • 表示服务器在执行请求时遇到了意外情况,导致无法完成请求。这个状态码通常用于表示服务器端出现了错误,而客户端无法处理或修复这些错误
    • 如:数据库 Redis 不可用、代码 Bug 导致 panic 或者依赖的某个下游服务请求超时等等

关于更多常用状态码的使用场景,后续在深入介绍。

OpenAPI 规范简介

通过上面的步骤,我们确定了登录 API 的所有细节,此时,一个很关键的问题是:我们的 API 如何管理?或者说如何分享给团队其他成员?使用何种工具?选择代码生成,还是手动维护?

这个时候,我们就需要了解 OpenAPI 规范 了:这是一种通过 json 或者 yaml 表达 API 的语法规范,可以理解成一种声明式编写 API 的语言,还记得初学 HTML 的时候吗?我们使用代码编辑器编辑 html 文件,然后通过浏览器进行渲染输出。

{
   
   
    "openapi": "3.0.3"
}

OpenAPI 规范也是同样的道理,我们在 VS Code 中编写,然后使用 OpenAPI (Swagger) Editor 插件进行预览,使用 redocly-cli 编译成静态 html 文件,通过 nginx,我们可以很方便的分享给任何人。

关于 OpenAPI 规范及其语法的更多细节,后续文章会深入介绍,这里我们先跳过,目前你只需要知道这是一个能帮我们很容易写出 RESTful API 文档的工具即可。

现在,让我们来创建一个 example.json ,其内容如下:

{
   
   
    "openapi": "3.0.3",
    "info": {
   
   
        "title": "console API文档",
        "version": "1.0"
    },
    "servers": [
        {
   
   
            "url"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值