怎么自动化处理前后端对接过程?这是一个问题

2,676 阅读9分钟

在开发的时候,前端和后端对接的过程中,需要对接很多的接口,编写接口的mock数据,如果项目用上了TS的话,还得为这些响应内容写ts类型,这个过程中几乎都是模板代码,很浪费时间。所以自动化这个过程的工具就提上了日程。分解一下,在部分的前端与后端对接过程中,大概是如下的几个步骤:

graph TD
接口文档输出 --> 写接口函数 --> 写ts类型 --> 写mock函数

在这个过程中,第2至4步基本上都是模板代码,写起来没啥大的变动,都是根据文档按照既定的规则写就好了。

但是按照以上步骤开发的话,会存在几个明显的问题:

  1. 项目中的接口数一般是几十、上百乃至更多,这么写下来会耗费我们大量的时间
  2. 接口发生变化的话,我们也需要同步的修改我们前端的代码
  3. 数据的mock类型都是基础数据,缺少根据场景来智能的mock数据

上面几点是需要解决的问题,如果说在我们的项目中可以做到下面几点:

  • 自动生成接口代码
  • 自动生成接口参数以及响应数据的类型代码
  • 生成的代码能够自动的同步接口文档的修改
  • 生成的代码可以根据项目具体场景进行二次修改
  • 能够智能的mock数据

那么就可以节约前端很多的开发时间,将这个时间更多的聚焦于业务的开发,同时避免了枯燥的模板代码编写,可以极大的提升开发体验。特别是肝业务的时候,定义类型代码再想个名字,想想都头疼。

本着不重复造轮子的思想,先找了一圈开源的第三方库,最终发现pontapifox结合使用可以有效的解决以上几个问题。然后就是再也不用写那些枯燥的模板代码了。由于篇幅有限,这里只是着重介绍使用频率高的功能,抛砖引玉罢了。

pont

pont是阿里开源的一个解决方案,他的官方介绍如下:

pont 在法语中是“桥”的意思,寓意着前后端之间的桥梁。 Pont 把 swagger、rap、dip 等多种接口文档平台,转换成 Pont 元数据。Pont 利用接口元数据,可以高度定制化生成前端接口层代码,接口 mock 平台和接口测试平台。

简而言之,它可以根据各种接口平台的通用数据,来生成前端的接口层代码ts类型以及数据模型。当然,这只是它的一部分特点,它还有如下的特性:

  • 跨语言 天然支持 Javascript 项目及 Typescript 项目。如果使用 JavaC++ 等语言,可定制代码生成器支持
  • 支持高度定制化 通过复写内部方法,各种高度定制化需求都可以满足
  • VSCode 插件支持 专门为 Pont 开发的 VSCode 插件 vscode-pont,完美支持 Pont 所有能力
  • 丰富的命令行提供丰富的命令行命令,满足不同场景的使用
  • 自动化 mocks 服务Pont 自动生成所有 mocks 数据,并提供所有接口的 mocks 服务

我们项目的技术栈是vue3 + TS,IDE用的是 vscode。接口文档数据是swagger生成的,pont还有专门的vscode插件可以使用。所以pont是非常适合做这件事的。

使用

使用的话比较简单,参考pont的github文档就可以了。 按照文档安装好依赖,点击插件的按钮就可以生成代码,下面是pont生成的各部分代码:

生成的接口代码

import * as defs from '../../baseClass';
import pontFetch from 'src/utils/pontFetch';

export class Params {
  /** The name that needs to be fetched. Use user1 for testing.  */
  username: string;
}

export const init = new defs.User();

export async function request(params) {
  return pontFetch({
    url: '/user/{username}',
    params,
    method: 'get',
  });
}

生成的类型代码:

// api.d.ts
declare namespace defs {
  export class Pet {
    /** category */
    category?: defs.Category;

    /** id */
    id?: number;

    /** name */
    name?: string;

    /** photoUrls */
    photoUrls?: any[];

    /** pet status in the store */
    status?: 'available' | 'pending' | 'sold';

    /** tags */
    tags?: defs.Tag[];
  }
}

declare namespace API {
   export namespace pet {
       /**
         * Find pet by ID
         * /pet/{petId}
         */
        export namespace getPetById {
          export class Params {
            /** ID of pet to return */
            petId: number;
          }

          export type Response = defs.Pet;
          export const init: Response;
          export function request(params: Params): Promise<defs.Pet>;
        }
  }
}

业务中使用

import './services/';

// defs 包含所有公共类型
const pet = new defs.Pet();

const data = ref<API.pet.getPetById.Response>(pet);
// API 包含所有接口
API.pet.getPetById
  .request({
    petId: 3
  })
  .then(p => {
    console.log(p.name);
  });


可以看到,生成的代码属于生产级的,可维护性较好。使用的话,前面已经说了,按照文档来就行了,这里不再多说。这里我主要想说说使用的时候遇到的一些问题

1、使用项目自己封装的请求库:每个项目都会封装自己的请求库,用于处理一些通用的诸如token或者是返回的业务码之类的逻辑,那么在pont里面,是可以自定义生成的模板代码,进而使用项目自己封装的请求库。

image.png

如上图,pontcore文件只要实现fetchgetUrl方法就可以集成自己的请求库,或者修改生成代码模板,直接写在模板里面也可以。然后这个文件尽量放到services文件夹之外,后面会说为啥

2、非必要不变动接口路径:pont使用的时候,会根据接口文档模型在项目的根目录下生成文件,文件结构如下:

image.png

其中mods是用来存放生成的各种接口代码的,它的默认文件结构是跟接口的路径相关联的。 比如一个接口的路径是 /paListEval/batchSaveRules,那么它的文件路径则如下

image.png

它的使用如下: API.paListEval.batchSaveRules.request().then(() => {});

这里值得注意的是,如果接口已经使用的话,那么修改接口路径的话,虽说自动生成接口的地方可以重新生成,但是前端已经使用的地方就要重新手写了,这里需要跟后端协商尽量避免这种情况。

3、接口文档字段的类型尽量准确:由于pont是根据接口文档(例如swagger)来生成类型代码的,而接口文档一般是后端来维护的。这个时候可能会遇到:

  • 类型与实际类型不符合,比如本来是number类型,结果文档是string类型
  • 返回的字段不是可选的,文档没有标识为必需,导致前端处理必须全部做非必要的判断处理,不然TS类型检查错误

4、接口更新:pont的可以设置每隔一段时间去检查服务器文档有没有新的变动,如果变动了则会更新本地生成的代码。这个功能使用体验不是很好,自动更新总是不能正确的更新代码。目前最佳实践是删掉整个目录,重新生成代码,也还能接受。

聊完了接口层代码生成这块儿,下面来说说mock,mock作为前后端对接不可或缺的一环,虽然pont也支持生成mock数据,但是跟下面的工具比起来,还是有差距的,专业的事情就交给专业的人做吧,下面来说说这个牛逼的工具

apifox

apifox是最近出来一个新的集API 文档、API 调试、API Mock、API 自动化测试于一体的工具。我选择用它的一个点主要在于它的mock功能非常的丰富。

我在之前的项目中使用的是mockjs来提供mock数据,它需要对每个接口的每个属性都定义mock规则,这个对于接口较多的项目,是一个非常痛苦的事情。而apifox的mock功能则非常强大。它体现在以下几个方面:

1、零配置:它可以根据接口的类型来自动mock数据。换句话说,如果你对接口返回的数据不需要精细化控制的话,它直接就可以用了。不再需要定义每一个接口了

2、智能mock智能mock功能可以通过正则匹配的方式,匹配到一些字段,给他们应用mock规则apifox有一些内置的规则,当然我们也可以自定义规则,而且,它还提供了诸如姓名图片等个性化数据,这里一般配置一些常用的字段mock,比如我项目中配置的几个

image.png

3、基于数据模型:它修改mock规则是基于数据模型的。也就是它不是仅仅修改的某一个接口的mock规则,而是修改的对应的数据模型的规则。修改完成后,其他应用这个数据模型的接口也会应用到新的mock规则,听起来好酷

4、除了接口的模型外,项目中也可以自己自定义一些模型。比如有一些字段需要返回一些数字的枚举,这个时候就可以定义一个数据模型,在任何可以使用它的地方引用这个模型就好了。

image.png

5、还有一个比较好玩的是云端mock,这个其实就是可以和团队共享你的mock规则,或者其他人因为某种需要访问你的mock

6、高级mock:这个可以根据请求参数的不同来返回不同的mock数据,这个功能在面对一些复杂的mock场景时比较有用。

看了以上强大的mock功能后,你难道不想试试吗?😃 当然,除了以上的mock功能外,还有其他一些比较实用的功能,比如接口自动测试化api调试等,可以参考官网

总结

目前呢,前后端对接大概就是上面那样了,接口代码的自动化部分由pont来做,mock部分就交给了apifox,通过与之前对比,开发体验上确实提升了很多,不用再去写大量的模板代码,而且这两个工具可以在项目的任意开发周期接入。但是要想玩的更好的话,除了前端,还需要后端配合,输出一份比较标准的接口数据文档,只有这样,后续依据接口文档数据才能生成最佳实践的代码。

当然如文章所写,也还是有一些瑕疵,这就交给后面的时间了。