ZanApi 让前后端协调更高效

一、当我们在说前后端协作的时候,我们在说什么

目前前后端分离已成为主流,前后端开发环境互相独立的情况下,如何提高前后端协作效率已然成为每个公司不得不考虑的问题。

以一个项目开发周期为例,在协作上一般需要面对以下几个问题:

  1. 项目开发初期,前后端需要就接口定义达成一致并且最好能在一个地方持久化,并且随着项目迭代开发持续维护
  2. 前后端在并行开发时前端需要先对接口数据进行 mock
  3. 项目联调前,对于前端同学来说,我们需要能科学的判断后端同学的接口是否真的达到可联调状态了

二、有赞之前是怎么做的

1. 对于接口定义

我相信很多公司跟有赞一样,没有专门的 API 文档站点,也没有相应的工具,基本在一个通用的文档站点由工程师自己手动创建、维护接口文档。

有赞也同样使用这种方式去维护接口文档,但这种方式会带来一些比较明显的问题:

  1. 创建、维护成本大,在后端同学比较忙的情况下,不见得可以及时提供、更新文档。
  2. 手动编写容易出错。
  3. 由于是通用的文档站点,接口文档展示并不是非常直观。

这些问题都会增加协作双方的沟通成本,进而影响项目整体进度。

2. 对于数据 mock

前端同学对于接口数据 mock 应该是非常熟悉的,而且每个公司或多或少都会有自己的一些套路跟方案。

比如最开始,大家可能会使用在前端代码里面直接写死 mock 数据的方式。你可能会对下面这段代码比较熟悉:

import mockData from './mockdata.js'

// ajax(url).then(dosomething)
// 数据 mock

setTimeout(mockData => {
    dosomething(mockData);
}, 1000);

通过这种方式,前端同学可以在开发阶段手动 mock 后端接口数据,从而实现并行开发。

但这种方式的缺点显而易见:

  1. setTimeout 显然是无法完全模拟 ajax 的行为的。
  2. 上线前需要修改代码,重新打包。
  3. 因为有缺点 2,会引入额外的风险点。(忘记修改重新打包)
  4. 是否要保留 mock 数据和相应的逻辑以便之后项目迭代。
  5. 如果后端接口变更,无法及时响应(依赖于前后端口头通知)

因为这些缺点和 nodejs 的崛起,前端同学自然会想到使用 node 做一套 mock 服务器。于是就有了下面这种方式:

// ajax(realUrl).then(dosomething)

ajax(mockUrl).then(dosomething)

这种方式解决了使用 setTimeout 模拟真实请求的问题并且极大的减少了 mock 功能对业务的侵入。而且因为 mock 数据在远程,前后端可同时修改,减少沟通成本。

但是这种方式还是无法解决问题 234

有赞就曾使用过这种方式的变体,我们依赖特定 ajax 库的全局钩子,解决了问题 234。但却也带来了其他问题,比如对特定 ajax 库的强依赖。

3. 联调状态判断

我相信很多公司跟有赞一样,联调时间是在项目开始的时候开发预估的,开始联调的时候前端其实并不知道后端接口是否真的 OK 了,或者说至少能调通了。所以常常会碰到的问题是,后端同学告诉你可以联调后,你发现接口报的全是 404 或者 500 ,最后一查是后端环境配置有问题。

其实有赞在之前也并没有找到一个比较好的方案,到现在也只能说还处于探索阶段。

三、那么到底什么样的协作方式是我们想要的

1. 对于文档来说

  1. 后端同学能快速生成文档,并且持续维护。
  2. 文档需要包含足够多的信息
  3. 友好的接口定义展示

2. 对于数据 mock

  1. 方便合作双方可同时修改,即时生效
  2. 最好可以自动生成随机返回值
  3. 能根据不同的请求参数返回不同数据
  4. 修改 mock 数据的行为,可以快速通知到合作方,避免双方对数据格式认知不同步

3. 对于更好的判断联调时间

通过比较科学的方式判断后端接口是否已经可被调用。

四、ZanApi 是如何做到的

首先,后端同学在写文档这件事上,成本是否可以为零?

有赞目前在大力推进服务化,并且引入了 node 作为中间层。所以在有赞,前后端的边界变成了 browser + node -> java 服务化接口

对于 java 同学来说,业界已经一些比较成熟的方案来生成接口文档,比如 swaggerapi blueprintswift

但这些方案要么需要 java 同学引入很多非项目的三方依赖,要么有它自己的一套接口定义方式从而增加 java 同学的工作量。

而且有些方案并不适用于目前越来越主流的 browser & node -> 协议网关 -> java 服务化接口 这种前后端协作方式。

1. ZanApi 的文档生成方案

方案

解决快速生成、更新文档的问题

为了让 java 同学更方便的生成文档,我们为 java 同学提供了IDEA Intellij 插件

最终的效果是,java 同学能够一键生成、更新接口文档。

plugin

解决文档数据问题及展示

我们在远程部署了一个 java 解析服务器,通过该解析服务,我们可以将 java 代码里的备注抽取出来生成接口字段注释。最终一个接口的返回值定义可能是这样的。
返回值示例

所以,如果 java 同学本身有比较好的写注释的习惯,那么对他来说生成一个合格的接口文档将是零成本的

2. ZanApi 的数据 mock 方案

目前有赞完整的数据 mock 方案如图所示:

mock方案

从客户端(pc / mobile)发起的请求在经过 ZanProxy 过滤后,将需要 mock 的接口打到 ZanApi 上,经过 ZanApi 返回 mock 数据。

解决可同时修改,快速通知的问题

由于 ZanApi 部署在远端,前后端可同时修改,所以本身天然没有这个问题。

并且在 ZanApi 系统上,你可以收到自己收藏的接口的 mock 数据变更通知,可以较快的感知 mock 数据的变更。

变更通知

支持多份 mock 数据,自动匹配

ZanApi 支持为同一个接口添加多份 mock 数据,请求在数据 mock 时,ZanApi 能通过请求参数,自动返回不同 mock 数据。

支持根据接口定义返回随机数据

当 java 同学通过 Idea 插件 自动生成接口文档时,ZanApi 会通过解析服务获取接口的返回值定义并自动讲定义转化成 JSONSchema 格式。

当需要返回随机数据时,ZanApi 可以根据接口返回值的 JSONSchema 定义产生随机数进而返回给客户端。

3. ZanApi 对联调的支持

在 ZanApi 上,你可以为每个接口创建不同环境下的测试用例。在测试用例的基础上,你可以以项目维度创建一个接口集合

接口集合创建完毕后,ZanApi 提供了 一键测试 功能。

一键测试功能会获取该接口集合内所有的接口,并将这些接口中定义的测试用例完整的跑一遍。如果其中某一个接口无法调通,那么 ZanApi 将提示你该接口测试失败。

甚至,ZanApi 允许你通过对比真实接口返回值和接口返回值定义(或者对比之前已存在的某个 mock 数据)来判断该接口是否符合预期。

比如,在接口的返回值定义中字段 count 是一个数字,但是 ZanApi 发现测试用例返回的真实数据中该字段是一个 string ,那么该测试用例也将不会通过。

UI 如下:

接口集合测试

五、最后

有赞技术开放日上介绍了 ZanApi 后发现大家对 ZanApi 还是有着比较大的兴趣。但是由于我们尚未有时间整理开源相关的事宜,并且确实 ZanApi 还有很多不成熟的地方啊,所以 ZanApi 开源在短期内应该没办法实现。

但我们一直有开源的计划,并为之努力着