Typescript前端接口联调自动化的探究与实践

源宝导读:Web应用程序一般都是前后端分离的基本架构,而前后端很可能分别是两拨人分别开发,前后端的接口连调成为高频沟通的对象,开发内耗最大的也在这个环节。本文将分享如何基于OpenAPI将前后端接口协议标准化和自动化,从而大幅降低开发内耗。

一、背景

  通常的前端开发中, 接口service层依靠人工阅读接口文档来手动书写, 然而大部分工作是重复的, 骨架是相同的,只是接口数据和接口路径等改变, 对于一个庞大的项目(比如接口数量几百个), 并且客户端存在多个情况下(比如h5和小程序还有android, IOS), 重复的劳动成倍增加, 而且维护起来也会非常麻烦和不可靠。

  重复的工作是,后端开发人员开发了一套接口,  前端开发又书写了同样一遍接口, 而且还要生成文档, 而这些接口可以统一成一份与语言无关的结构化的描述, 前端可以利用code-gen自动生成可调用的service层。

  而且对于现在基于Typescript前端的开发,  接口协议生成的数据interface应该直接拿来使用, 用来约束各个业务模块的数据结构, 如果要组合生成新的数据结构, 应该使用Typescript的高级类型来组合生成(比如Pick<>,Required<>, Partial<>, Omit<>),  这样前端的业务组件数据结构将和接口协议描述保持一致。

1.1 传统前端后端联调模式问题: 不可靠, 重复工作量, 低效

  • 整个过程写了两份协议, 服务端一份, 客户端一份, 工作重复。

  • 联调周期很长,并且需要不断的重复沟通, B发布了一项接口参数更新, 需要通知C去查看文档, 那么C有这么一个待办事项, 什么时候执行大多数时候不得而知, 过了一段时间C查看了文档之后发现有几个地方不合理, 那么又通知B, 这样联调的周期又延时又低效。

  • 令人忽视的一点是注释, 同一个接口描述, 同一个参数的描述可能存在3种描述, 这可能让团队每个人对业务的理解都不一样。

1.2 Typescript前端项目的特点

1.2.1 可使用丰富的高级派生类型

  • 业务模块中的子组件的数据结构一般是派生的子类型

  • 当SampleInterface结构发生变化,派生的类型会自动继承其中的属性, 如果有冲突, ts会给出错误提示

1.2.2 开发过程数据结构优先

  • 前端的业务模块中:显示, 交互等与用户相关的功能操作都是围绕数据来进行。

  • 前端开发, 扩展, 维护和重构等工作也是围绕数据来进行。

  • 并且业务模块的数据结构与接口的数据结构有很强的关联性。

基于以上特点将数据结构定义来源单一化, 使业务数据定义更合理:

  • 单一源化数据结构定义, 有利于统一维护, 利于重构。

  • 当service接口数据结构发生变化, 那么派生的数据结构会自动适应, 如果有错误, 能够根据Typescript语法提示完成重构, 最后再根据语法提示修改相关的业务相关的组件。

  • 前端业务组件大部分数据结构与API接口的数据结构是关联的。

能不能通过某种接口协议自动生成Typescript的接口定义呢?
Swagger Open API协议,  protobuf协议等都是可以描述RESTFul API接口。

二、前后端联调的优化解决方案: 以API协议为中心

  • 按照之前的思路的理解: 特定的业务逻辑的数据结构在不同的业务组件中是高度一致的, 一个数据结构的定义应该只存在一份, 不应该手写多份。

  • 前后端维护唯一一个的规范来描述接口定义。

  • 不同的客户端语言可以根据这个协议生成可执行的接口。

2.1 步骤

2.1.1 基于Open API Specification (Swagger)协议的转换研究

  OAS用来定义一个标准的, 与编程语言无关的RESTFul API的接口,  可提供给计算机解析, 也可进行人工阅读和分析, 是一种能结构化描述API接口的约定, 而目前主流的文档生成工具都支持这种标准, 可实现个性化需求。

  OAP协议可以用JSON Schema来定义, 详细可看:  https://swagger.io /specification /v2/

基本结构:

对应的Typescript示例:

2.1.2 生成Typescript目标代码实际项目中的分析

  命名空间根据项目的业务模块来区分, 在Swagger协议中一般在tags里做为标记:

2.1.3 利用模板引擎mustache生成代码

  • 使用编程语言将原始的Swagger JSON转换成更加直接并且有丰富变量的模板数据。

  • mustache模板是根据项目实际来设定, 灵活使用不同模板生成不同的目标代码。

  • 遇到少量 的特殊的接口, 可以过滤不生成, 然后手动实现接口即可。

  • 具体项目在 https://github.com/mmmy/swagger-typescript-gen。

2.2 实践结果

  参考了一个nodejs的开源转换工具, 修改增加了模板数据变量和模板:

  • Pulsar前端接口220+, code-gen生成了7000+行代码。

  • dmp前端接口250+, code-gen生成了9000+行代码。

  后端生成的Swagger response中字段缺少必填属性和枚举属性, 生成的接口相应Typescript数据结构都是可选参数。

   遇到的问题:类似递归的结构暂时无法生成:

  遇到少量接口不能实现, 可以手动实现该接口。

  不需要看api文档, 却能发现文档的很多问题:接口定义了一个query参数 还有一个类型为json的body参数。

  还有少量的接口未定义返回参数, 实际上有返回参数。

2.2.1 带来的优势

  • ✅一致性

      前端的接口调用参数, 描述等任何信息将与协议一键同步。

  • ✅重构优势

      如果业务逻辑上接口发生变化, 将会自动影响相关的业务组件, 按照Typescirpt的提示能完成绝大部分工作。

  • ✅减少工作量

  前端不需要再去查看API文档, 手动同步书写接口代码, 后期维护也是维护源头的协议。

三、结合Typescript开发模式进一步优化

  假设所有的模块都是具有完备的typescript设计和定义,为什么运行时还是会报语法错误, 类型错误?

  Javasctript本身是动态弱类型语言, 运行时并不能保证红色箭头输入是合法的, 比如预期某个接口返回一个值为对象Object, 但是实际返回了一个null, 为了兼容, 不得不在每个组件中对很多值进行空值判断, 来防止运行错误, 实际上不应该在B中做无意义的判断, 因为在组件A中已经给了B正确的类型输入, 正确的做法是处理和兼容红色的输入, 来确保输入到A的值是合法的, 所以你对输入数据不确定的代码处才是问题的根本, 这和Tyepscript本身没有关系。

3.1 在数据进入组件之前进行纠错, 前端0错误成为可能

  假设服务端的数据完整性是不可靠的, 比如对象和数组可能是null, 但是协议定义的却是必要的, 不能是null, 这样给前端运行时带来风险, 所有对这些空字段可以做空默认值处理, 这个操作可以在前端获取到数据的时进行校验并赋予默认值, 这样业务组件拿到的数据不会存在空类型操作错误。

四、总结与展望

  • 基于协议为中心的前后端联调模式可以为软件开发带来益处, 特别是对于Typescript项目, 摒弃掉了低效的重复的工作, 让工作更集中在具体的业务实现方案上。

  • 本次研究只是实现了基本的RESTFul的常规接口,模板也相对复杂度不高, 并不能完全处理通用Swagger协议,比如参数在路径中, 不同http状态码的处理。

  • 对于其他平台还需研究, 比如小程序, Android(Java), IOS(Object-C)。

------ END ------

作者简介

杨同学: 前端工程师,目前在云技术创新中心负责DMP产品的研发工作。

也许您还想看

云客后台优化的“前世今生”(一)

云客后台优化的“前世今生”(二)

在明源云客,一个全新的服务会经历什么?

“弱中心”化的分布式配置管理技术可行性探索

基于 Go 的微服务运行情况监控实践

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/307324.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

leetcode51. N 皇后(java详解)

一:题目 二:上码 class Solution {/**思路:1.先说我们选用的数据结构;我们是选取的是List<List<string>> ans 来存每次的结果;我们在创建这个二维矩阵的时候用的是char的二维数组,那么的话等到我们得到一种可行解的时候 将char的二维数组每一行转换成 String 并存…

程序员如何跨越35岁危机?这篇给点干货建议!

职场&认知洞察 丨 作者 / findyi这是findyi公众号的第83篇原创文章这两天在我的读者群里做了一个职业小调研&#xff0c;发现关注我公众号的70%以上都是程序员。毕竟程序员吸引程序员&#xff0c;这也算猿粪吧&#xff0c;哈哈。这个小调研也引发大家对程序员行业的激烈探讨…

leetcode455. 分发饼干

一:题目 二:上码 class Solution {public int findContentChildren(int[] g, int[] s) {int ans 0;int gIndex 0;int sIndex 0;Arrays.sort(g);Arrays.sort(s);while (gIndex < g.length && sIndex < s.length) {if (s[sIndex] > g[gIndex]) gIndex; //只…

写了多年代码,你会 StackOverflow 吗

写了多年代码&#xff0c;你会 StackOverflow 吗Intro准备写一个傻逼代码的系列文章&#xff0c;怎么写 StackOverflow 的代码&#xff0c;怎么写死锁代码&#xff0c;怎么写一个把 CPU 跑满&#xff0c;怎么写一个 OutOfMemory 的代码。今天主要来看 StackOverflow&#xff0c…

C#实现迭代器

迭代器模式&#xff08;Iterator&#xff09;&#xff0c;提供一种方法顺序访问一个聚合对象中的各种元素&#xff0c;而又不暴露该对象的内部表示。C#中使用IEnumerator接口实现&#xff0c;Java中使用Iterator接口实现&#xff0c;其中原理都差不多&#xff0c;下面我就用C#代…

从CLR GC到CoreCLR GC看.NET Core为云而生

内存分配概要前段时间在园子里看到有人提到了GC学习的重要性&#xff0c;很赞同他的观点。充分了解GC可以帮助我们更好的认识.NET的设计以及为何在云原生开发中.NET Core会占有更大的优势&#xff0c;这也是一个程序员成长到更高层次所需要经历的过程。在认识GC的过程中&#x…

springboot邮件发送(牛客论坛项目之QQ邮箱发送)

一:邮箱发送原理 1:狂神图解 张三通过smtp协议连接到Smtp服务器&#xff0c;然后发送一封邮件给网易的邮件服务器网易分析发现需要去QQ的邮件服务器&#xff0c;通过Smtp协议将邮件转投给QQ的Smtp服务器QQ将接收到的邮件存储在456789qq.com这个邮件账号的空间中李四通过Pop3协…

如果淘宝双十一架构用. Net Core,如何“擒住”高并发、高可用、低延迟?

电商的秒杀和抢购&#xff0c;对我们来说&#xff0c;都不是一个陌生的东西。然而&#xff0c;从技术的角度来说&#xff0c;这对于Web系统是一个巨大的考验。当一个Web系统&#xff0c;在一秒钟内收到数以万计甚至更多请求时&#xff0c;系统的优化和稳定至关重要。缓存技术是…

.NET5在开发平台上远优于Java,如何发挥优势?

上周.NET5 RC2已发布&#xff0c;.NET5已经肉眼可见的即将到来&#xff0c;令人期待&#xff01;从.NET Framework到.NET Core再到.NET5&#xff0c;能看到诸多开发者和公司都在积极拥抱新技术。对比Java&#xff0c;国内主流开发都还停留在Java8&#xff0c;在云原生的互联网时…

leetcode122. 买卖股票的最佳时机 II

一:题目 二&#xff1a;上码 class Solution {/**思路:1.局部最优:我们买入当前股票等哪天遇见最大值的时候买出 赚最大利润2.全局最优:局部最优推出全局最优3.这个利润是可以被分解的 7 1 5 10利润: -6 4 5那么最大利润是459其实就是1买入10卖出,但是我们可以在5这天…

多重继承和菱形问题

翻译自 John Demetriou 2018年4月8日 的文章 《Multiple Inheritance And The Diamond Problem》[1]开篇之前&#xff0c;我假设每个人都知道在面向对象编程中继承是什么&#xff0c;以及它能提供什么好处。我不会深入探究对象继承的基础知识。这篇文章更关注于多重继承和它所面…

Jekins持续集成在ERP研发中的应用实践

源宝导读&#xff1a;“持续集成”是敏捷最佳实践中&#xff0c;保证高质量交付的关键环节之一。本文将介绍明源云ERP系统在研发过程中&#xff0c;应用Jekins平台完成持续集成自动构建的实践。一、认识持续集成持续集成是一种软件开发实践&#xff0c;即团队开发成员经常集成他…

leetcode45. 跳跃游戏 II(java详解)

一:题目 二:上码 class Solution {public int jump(int[] nums) {int ans 0;int curIndex 0;//当前统计出来的可以移动的最远距离的下标int nextIndex 0;//在到达 当前最远距离下标的这段距离内 我们统计出的可以达到的最远距离//如果在统计的过程中 其覆盖范围已经大于数组…

Ids4 认证保护 API 方案更新

壹时刻保持学习的喜悦可能你咋一看这个标题不知道什么意思&#xff0c;其实我也没想好怎么表达&#xff0c;因为是一个特别简单的小知识点。先说下为什么突然说到了Ids4&#xff1f;这几天大家都知道&#xff0c;我在视频《微服务之eShop讲解》&#xff0c;目前讲到了购物车微服…

dotNet Core 3.1 使用 Aspose (部署 Docker)

在之前的文章《dotNET Core中使用Aspose&#xff08;部署Docker&#xff09;》中介绍了在 dotNet Core2.1 中使用 Aspose &#xff0c;并部署到 Docker 中&#xff0c;现在 dotNET Core 升级到了 3.1 &#xff0c;Docker 镜像发生了变化&#xff0c;一些依赖的安装也有些变化。…

MySQL之一条Update的执行流程

文章目录1:执行的语句2:在更新操作中流程中特有的部分(1):redo log&#xff08;重做日志&#xff09;(2):binlog&#xff08;归档日志&#xff09;(3):Redo日志跟binlog日志的区别2:执行流程1:执行的语句 update T set c c 1 where ID 2;2:在更新操作中流程中特有的部分 (…

教你打入clr内部: 配置windows上的windbg,linux上的lldb

一&#xff1a;背景1. 讲故事前几天公众号里有位兄弟看了几篇文章之后&#xff0c;也准备用windbg试试看&#xff0c;结果这一配就花了好几天&#xff0c;(づ╥﹏╥)づ&#xff0c;我想也有很多跃跃欲试的朋友在配置的时候肯定会遇到这样和那样的问题&#xff0c;所以我觉得有必…

leetcode周赛6076. 表示一个折线图的最少线段数

气死爹了 用C过不去 换成Java 过了 一:题目 二:上码 class Solution {public int minimumLines(int[][] stockPrices) {Arrays.sort(stockPrices,(o1,o2)->o1[0]-o2[0]);int n stockPrices.length;if (n 1) return 0;int ans 1;for (int i 0; i < n-2; i) {int k1 …

使用代码片段的正确姿势,打造高效的vscode开发环境

全文3928字&#xff0c;阅读时间 10分钟&#xff0c;未来节约时间 15分钟/每天代码片段&#xff08;code snippet&#xff09; 相信大家都或多或少有接触过。在完成一个项目以后&#xff0c;往往都会写出许多有价值的代码&#xff0c;或是绞尽脑汁解决的难题&#xff0c;或是灵…

leetcode周赛6074. 字母在字符串中的百分比

这个简单题也比较狗 上午做的时候一直有个测试点不过 但是题目不给出什么测试点不过 原来是100这个答案 给跪了 一:题目 二:上码 class Solution { public:int percentageLetter(string s, char letter) {if (s.size() 0) return 0;int count 0;for (int i 0; i < s.si…