基于OPENAPI v3 的前后端集成与分析
什么是OAS
OpenAPI Specification(简称OAS)为 RESTful API 定义了一个标准的、与语言无关的接口,它允许人类和计算机在不访问源代码、文档或通过网络流量检查的情况下发现和理解服务的功能。正确定义后,消费者可以使用最少的实现逻辑理解远程服务并与之交互,然后,文档生成工具可以使用 OpenAPI 定义来显示 API,代码生成工具可以使用各种编程语言、测试工具和许多其他用例来生成服务器和客户端[^1],截止目前版本3.1.0。
换句话说就是定义一个规范用来描述基于RESTful风格的API,基于API可以对其进行测试,自动生成等其他功能,也就是服务和服务之间的一种“契约”形式。
OAS 历史
OAS也被称为Swagger Specification,在2016年后从Swagger Framework中独立出来成为Linux开源项目[^2]。
历史时间线:
- 2011年8月11日,Swagger 1.0 首次发布
- 2014年9月8日,Swagger 2.0 发布
- 2015年11月,Swagger拥有者SmartBear Software将Swagger规范捐献给OpenAPI组织,同时还有一个规范的竞争者RAML[^3]和API Blueprint[^4]
- 2016年1月1日,Swagger Specification名称变更为OpenAPI Specification
- 2017年7月26日,OpenAPI发布3.0.0版本。
- 2021年2月17日,OpenAPI发布3.1.0版本。
最新参考OAI - Github Release Note
前后端分离的痛处
对于前后端分离的原因和技术不做讨论,但是为了更好的讲解痛处,请参考如下内容:
- 为什么要前后端分离: 《前、后端分离,谁值得拥有?》
- 如何进行前后端分离: 《前后端分离实践》
言归正传,前后端分离解决了团队分工协作问题,让两端可以只关注自我领域内的知识和内容,减少相互依赖,但同时也带来“沟通”成本上升和如何保证系统之间稳定性的问题。
一个比较常见的场景是,前端团队的工程师和后端团队的工程师拿着笔记本,对着IDE开始商讨API接口实现的功能,路由地址,输入和返回参数,稍微负责任一些的工程师还会约定一些异常场景等,最终达成“口头”协议,待前后端开发完成后进行联调测试,大概率还会在处理/修改一些“细枝末节”的问题。某一天,前端界面一功能请求响应失败,发现原因是后端接口变动导致请求异常但未通知到前端工程师修改相应代码,异或是在接口变动后负责测试的人员,没有考虑到一些特殊的情况。这里暂且称之为前后端分离1.0场景。随着时间的发展,越来越多的人开始对如何保证前后端分离之后的软件质量进行思考,以Martin Fowler等人提出契约测试来使用自动化测试保证API接口的稳定性,同时集成CI/CD进行全生命周期的集成和监控,做到了API监控的自动化[^5]。其中衍生出了消费者驱动测试开发(Consumer Driven Contract)和Pact等契约测试框架工具进行实践[^6],这里暂且称之为前后端分离2.0场景。
对于前后端分离有几个技术关键点:
- 选用那种“契约”来描述API接口,是Swagger Spec,RAML Spec,还是以Pact框架为基础的Pact Spec[^7]。
- 如何保证“契约”的约定效力,是基于口头约定的Swagger-UI展现还是基于自动化测试的Pact测试框架。
- 如何保证“契约”的实时效应,是基于持续集成平台/工具的实时输出,还是团队之前达成默契保持人员沟通顺畅。
对于情绪化人的行为不可控的前提下,选择“机器”是不二法则,当然,“制造”复杂而又完美的机器也是要有成本的。
基于OpenApi Spec + CodeGen + Typescript的一种解决方案
虽然对于完美实现需求的Pact测试框架来讲,已经能满足目前需要的各种场景和功能。对于一些“小而美”的项目而言,即使在社区提供各种不同语言客户端和服务端之后还是显得略微重了一些,同时增加测试的成本也会给小项目带来不少的负担。所以,有没有一种既能保证一定程度的契约有效性或者说保证契约“部分”正确性的前提下,减少一些开发量?
这里给出一些经验总结:
- 不可缺舍:基于一种规范的API描述,正所谓无规矩不成方圆。
- 可取舍:基于契约的完备测试,测试的数量往往决定对业务功能覆盖的范围大小,牺牲一部分对业务功能的约束能力。
在这里提出一个组合假设:使用OpenAPI规范+Typescript增强Javascript的类型约束和智能感知,来保证API路由和参数的稳定性,不保证业务稳定性,不增加对接口的测试。
步骤1:以SpringBoot作为后端服务启动,并增加SwaggerUI依赖,启动服务后即可登录到SwaggerUI界面来获得最新的接口文档。
步骤2:使用Swagger官方提供的代码转换工具,将OpenAPI Specification转换为基于Typescript的前端API库。
步骤3:将前端API库导入到前端项目中,结合Axios或者其他HTTP库使用。
方案的一些不足之处
首先,强依赖后端对接口描述的完整性,如对于PathParameter必须强制在Controller中标明。 其次,由于OpenAPI规范中使用Controller其中的方法名作为API路由的唯一值Id,并且是全局唯一,如果在不同的Controller中存在相同名称就可能导致OperationId带有数字后缀,可能导致使用不同的API错误,包括多次编译/重新部署后可能Id相同但实际的API并不形同的问题。 再次,Code Generation工具基于Java以及Java JVM可能对纯前端开发并不友好。
最后,由于没有对API的业务逻辑进行覆盖,缺少了一部分API的稳定性保障,可是尝试使用Pact的方案,请参见文章《聊一聊契约测试》,文章中难免有不足之处,欢迎留言指正。
引用
[^1] Swagger官网介绍
[^2] Wiki关于OAS的历史
[^3] RESTful API Modeling Language
[^4] Blueprint
[^5] 契约测试
[^6] 聊一聊契约测试
[^7] Pact规范