大多数开发者可能都用过 Postman,根据其官网的介绍:Postman 是一个用于构建和使用 API 的 API 平台,简化了 API 生命周期的每个步骤,提供更便捷的团队协作,因此可以更快地创建更好的 API。这里的 API,除了我们常用的 HTTP API 之外,还包括 Websocket(BETA),gRPC。本文中,我们将以最常用的 REST API 作为例子。
假设我们在开发一个类似微博的项目,你是一个后端开发人员,前端分为手机端和网页端,而由于采用了 RAD 或者敏捷开发方法,你随时需要将在开发环境测试好的最新的 API 改动发布至测试环境(或 Stage 环境),并为测试人员或者前端开发人员提供最新的 API 文档。下面我们看看在这个过程中,Postman 能如何帮助简化 API 声明周期以及提供更便捷的团队协作。
开发阶段
在这个阶段,不管后端使用什么语言开发,最终开放的是 REST API 接口,在本文的示例中,我们使用 Jmix 框架开发基于服务的 REST API。Postman 的最基本用法,就是开发人员可以在这一步建立一个 API 集合(Collection),其中包含项目的所有 API,这里我们创建了一个叫 Corp
的集合,包含所有功能的 API:
单个请求
图中重要的三个部分:
- API 集合
- 单个 API 的请求方式(POST)和请求地址
- 单个 API 请求体
到这一步为止,就是 Postman 的基础用法了,我们创建一个 API 集合,而集合是支持导出的,可以导出为 JSON 文件,再发给其他同事,他们可以导入到 Postman 里面使用。
使用变量做第一次优化
在上面的图中,我们展示了集合中的第一个接口 - 获取 Jmix 本地 token。而这个 token,我们需要在以后的每个请求中都用来做用户认证。如下图:
请求认证
这里有一个问题,就是 token 会过期,比如我们今天拿到的 token,可能明天就没法再次使用了。而我们需要再次获取 token,然后挨个复制到每个请求中吗?这个未免太麻烦了。Postman 提供了环境变量的机制。有三种类型的变量,分别是:
- 全局变量(Globals):顾名思义,这里定义的变量在所有集合的所有 API 中都可使用。
- 集合变量:在集合中,有一个
Variables
标签页,可以定义集合级别的变量,这些变量,只能用于集合内的 API。 - 环境变量:需要建立一个环境变量的集合,这里面可以定义一组该环境内的变量,可以用在任何集合。后面我们会说到用法。
Postman 变量定义
我们可以声明一个名为 jmixToken
的集合变量存储 token,至然后在请求中使用 {{jmixToken}}
的方式引用变量即可:
token 存储
除了 token 之外,我们在 API 中使用的相同类型的参数也都可以声明为变量,而变量可以用在请求的任何部分。例如,我们在发新帖的 API 中使用的请求体如下,我们分别使用了 Postman 提供的随机生成 UUID 的 $guid
变量、集合中存储测试用户 Id 的 userId
变量,以及存储我们博客地址 https://blog.abmcode.com
的 blogUrl
:
{
"postId":"{{$guid}}",
"userId":"{{userId}}",
"content":"欢迎访问:{{blogUrl}}"
}
使用脚本进行第二次优化
经过了上面的第一轮优化后,我们的 API 里面会多了许多变量。但是还存在一个问题,就是我们在拿到 token 后,仍然需要手动更新一下 jmixToken
这个变量,否则各个 API 仍然使用的是过期的 token。这还是有点麻烦。
好在 Postman 提供了测试脚本的功能,可以解决这个小麻烦,我们需要在获取 token 的请求中编写一个测试脚本,用于更新 jmixToken
,这样我们一旦重新获取了 token,就可以保证其他 API 使用的是最新的 token。
编写代码的位置如下图所示,在 API 的 Tests
标签页。并且更贴心的是,Postman 在右侧给了一些常用的代码片段,点击即可使用,例如,获取全局变量、设置集合变量等。
测试脚本
测试脚本是 JavaScript 的,可能需要有一点 JS 基础,具体每行的作用,请参考注释。这里我们对返回结果做了两个测试,分别是验证 HTTP 状态码必须是 200 以及检测返回结果中必须包含 access_token
这个属性。需要注意的是,这两个测试如果有任意一个失败,都将抛出异常直接退出 JS 的执行,此时不会走最后一句设置变量的语句:
// pm.test 表示这是一个测试。
pm.test("Set Global variable jmixToken", function () {
// 测试 1 - 返回状态码为 200
pm.response.to.have.status(200);
// 获取返回结果的 json
var jsonData = pm.response.json();
// 测试 2 - 返回的 json 中必须有 access_token 字段
pm.expect(jsonData).to.have.property('access_token');
// 设置全局变量 jmixToken
pm.globals.set("jmixToken", jsonData.access_token);
})
这里我们还可以做一点优化,那就是针对上面代码中的 “测试 1”,我们检查了 HTTP 的返回状态码为 200,其实针对所有的请求,我们可能都需要做这个检查,那么如果不复制粘贴代码,有没有简化的方法呢?
有的,Postman 提供了集合级别的测试脚本,定义在集合中的测试脚本,会对每个 API 都适用。比如,我们可以把验证 HTTP 状态码的测试放到集合中:
集合测试脚本
小结
到这里,我们开发阶段对于请求的优化就结束了,通过使用变量,可以优化 API 中的数据,将相同的数据都定义在变量中。通过测试脚本,我们可以对 API 进行测试,也可以更新各种变量,避免手动修改的麻烦。我们的示例中演示的更新 token 是最常见的脚本功能,除此之外,比方说我们要测试的发帖和回帖功能,可以在发帖后将帖子的 ID 保存在变量中,测试回帖功能时,直接使用变量存储的帖子 ID,这些具体的业务场景,可以根据项目灵活变化。
测试阶段
开发完成后,我们就需要将 API 部署至测试或者 Stage 环境,交给测试人员或者前端开发人员进行试集成了。那么在这个阶段,你或许想在测试人员工作前自己先测试一遍,或者如果测试有问题,而你作为后台开发人员,也难免需要直接调用测试环境的 API 观察输出结果。这就有了一个新的问题:我们在之前的接口定义都是 http://localhost:8080
开头的地址,怎么能方便地切换到测试地址呢?
答案还是用变量。但是这一次,我们使用的是环境变量集合。
例如,我们可以创建两套环境变量,分别为 env_dev
和 env_prod
,其中都定义了变量 jmixAppUrl
,在 env_dev
中,该变量的值为 http://localhost:8080
,而在 env_prod
中,该变量的值为 https://your.test.env.ip:test_port
,然后修改每个请求,将原本的 http://localhost:8080
地址换成变量 {{jmixAppUrl}}
:
环境变量集合
使用时,通过右上角的环境变量集合切换功能,就可以切换不同的环境了。
发布文档
如果你的测试或者前端也使用 Postman,那么可能导出 API 集合文件再交由同事导入,可能是比较方便的方法。但其实 Postman 在文档发布这个功能上,也做了不少工作。
右键点击集合,有一个 View documentation
菜单,或者通过下图的按钮也可以查看集合的文档
集合文档
在查看文档时,右上角有一个 Publish
按钮,可以将你的文档公开发布,并提供一个 URL 地址用于访问。这样的话,其他同事如果不使用 Postman,只需要访问该地址,就可以看到 API 的文档。
发布文档
在发布时,可以选择环境变量集合,这样会用集合内的变量值直接替换 API 中的所有变量,这样一来,看文档的人不会读到看不懂的变量。下图是一个发布的文档示例,前端用户还可以根据编程语言,选择对应的代码样例:
发布的文档
发布后的文档会实时更新,也就是说,任何你在 Postman 中对集合 API 的修改都会实时同步至文档中。比如新增或删除某个 API、修改 API 请求体等等。
项目级别优化
其实,我们最后还做了一个项目级别的优化,这个案例可能不具有通用性,但是也可以给大家一个思路:
公共 API 抽离
由于我们的项目后台都是基于 Jmix/CUBA 框架开发的,因此,我们做了如下改动:
- 新建 Postman 集合 - Jmix/CUBA 通用接口,其中包含了 Jmix 和 CUBA 各自获取本地 token 的 API,以及从我们 SSO IDP 获取 token 的 API。
- 新建全局变量存储 token,全局变量有
jmixToken
,cubaToken
,ssoToken
。并且在上述三个接口的测试脚本中,分别更新这三个全局变量。
这样做的好处是,不需要在每个项目中单独提供获取 token 的 API,并能保证获取的 token 全局可用。
统一添加 Authorization 请求头
在业务 API 集合中,我们为 Collection 添加了 Pre-request Script
,这个脚本会在集合内的每个请求发出前先执行。我们就是用这个脚本为请求添加请求头,代码很简单,例如,对于使用 ssoToken
和 jmixToken
的 Jmix 项目,我们是这样做的:
请求头脚本
因此,对于集合内的每个请求,不需要单独设置 Authorization 请求头了。
统一业务 API 返回结构
最后,我们在代码层面对每个业务 API 的返回结构做了统一,都使用这样的返回结构:
public class RestResult<T extends Serializable> implements Serializable {
/**
* 业务状态码
*/
private int businessCode;
/**
* 提示信息
*/
private String msg;
/**
* 数据
*/
private T data;
//...
}
我们为所有的成功返回都定义了同一个 businessCode
,这样的话,在 Postman 的 Tests 脚本中,可以添加代码直接检查业务层面的返回结果是否成功,例如,我们定义 10000 为业务结果正确的返回值:
pm.test("Success return", function () {
pm.response.to.have.status(200);
pm.expect(pm.response.json().businessCode).to.eql(10000);
})
结语
本文介绍了一些使用免费 Postman 的进阶技巧:变量、脚本、文档发布。而现在 Postman 也在往 SaaS 方向发展,推出了团队协作功能,像文档发布、API 导出导入这些功能在团队模式下用不到了,因为 API 集合可以协作完成,文档也可以团队内共享。Postman 作为一款 API 平台,确实能在一定程度上提升团队的开发效率和协作。