TeaDSL:支持任意 OpenAPI 网关的多语言 SDK 方案
正在上传…重新上传取消
导读
在以云计算为主角的开发者视界中,OpenAPI 是绝对的主角。要发短信,用 OpenAPI;要管理资源,用 OpenAPI;要管理权限,用 OpenAPI。如果一个 OpenAPI 解决不了你的问题,那就再来一个。在今天,开放平台及 OpenAPI 随处可见,它是系统与系统之间集成的重要桥梁。但 OpenAPI 用起来是否真的舒服,这要打一个大大的问号。本文将介绍 OpenAPI 领域下的难题和一些解决方案。
背景
阿里云有位工程师叫朴灵,热爱开源,是活跃在 Github 上的国内技术大牛之一。在阿里工作 6 年之际,朴灵产生了离职的想法,打算去一家创业公司再战高峰。走之前,朴灵做了一些研究工作,他发现阿里云在功能和产品上可以说是一流的云计算厂商,是创业公司的首选,但由于过去的业务中写过大量的 Node.js SDK,对开发者体验有着自己的体感,他觉得在开发者体验关怀上,阿里云做得还不够好。来自一个热血工程师最朴素的想法,自己何不先留下来,去把这件事情做好,于是,朴灵加入了阿里云开放平台负责 SDK 业务,期间,他和团队研发了专利 TeaDSL,下面朴灵将分享 TeaDSL 如何解决多语言 SDK 的问题。
使用 OpenAPI 的痛苦
在过去,我们经常说的 OpenAPI,通常的做法是,开发好服务端的接口,然后在文档里简单写几个参数描述,就直接丢给客户去用。反正我是开发好了,我这里是好的,客户能不能用起来我是不用管的。
正在上传…重新上传取消
图 1 第一代的 OpenAPI 通常仅由简单的文档及实际的接口构成
然而接下来的问题就来了。首先,文档上写得不清不楚的参数,没有试过,完全不知道它到底能不能 Work。其次,OpenAPI 总得有一定的权限认证吧,那么总得有一个签名啥的,每个客户都要写一遍,关键是总是没法写对。再次,不同的客户所使用的编程语言不一样,得把接口重新包装才能用。
总算费心费力调通了接口,以为可以高枕无忧的时候,咋接口老是报错,网络连不上,返回的数据不对,诸如此类。再往后,OpenAPI 可能总是要发生一点变化什么的,总是出现一些数据结构发生变化,不兼容之类的问题。
一个 OpenAPI 到最后,不光是用户使用起来觉得很气,作为维护者也是很艰难的。当公布一个 OpenAPI 后,第一步给出简单的文档后,会发现除了要把参数详情写得越来越完善准确外,还得给出签名算法,让不同语言的开发者来接入。然而给出签名算法后,会发现只有一些开发者能顺利完成,大部分的开发者只能眼巴巴地请你帮忙提供一个 SDK。好吧,那就提供一下我最拿手的 Java 语言的签名,提供一个核心 SDK 呗。
图 2 第二代的 OpenAPI 会有 SDK 的实现,但仅有少许的语言支持
随着这个 OpenAPI 接口的用户越来越多,一个客户说我要用 C++ 来对接你,另一个客户说我要用 Python 来对接你,于是,我一个 Java 程序员,怎么就要写那么多语言的 SDK 呢。没有办法,如果不提供良好的 SDK,客户说,没有 IDE 提示呢,我怎么写代码呢。
总而言之,在 OpenAPI 的应用过程中,一件简单的事情,会变得非常复杂:
- 需要提供良好的 API 文档,作为最基本的要求
- 需要提供 SDK,保障开发者的编码体验,封装细节,代码提示等
- 需要提供 Code Sample,更理解接口的使用效果
- 如果有 CLI 就更好了,这样连 bash 脚本写起来也更方便
- 如果没有 Test Cases 作为日常的持续集成,接口质量可能存在问题
上面这些要求,如果加上多种编程语言的条件,就会演变为一件细碎而又繁多的体力活。并且这中间不能有任何的变动,因为仅仅是一点点的 OpenAPI 变动,就需要连带整个下游发生变化。如果一个地方没有保持一致,那么客户问题就会出现。
转存失败重新上传取消
图 3 当用户量变多,OpenAPI 的提供者需要提供完善的工具及更多的编程语言支持
通常为了解决此类的问题,以及 OpenAPI 的诸如签名校验,限流,生成 SDK、文档等等,业界通常会使用 API 网关来承担这些横向的责任。
然而,作为笔者所在的环境下,会发现,我们身边的网关有点多。于是不同的网关有不同的风格,不同的签名算法,不同的序列化格式。于是上述的过程要根据不同网关的数量,进行翻倍:
图 4 当一个企业变得庞大时,不同风格的 OpenAPI 及网关都会出现
当我们在抱怨使用不同产品的 OpenAPI/SDK 体验不一致,文档不对,Demo 出错等等问题时,真不是因为做这些事情太难,而是太多,太琐碎。一件简单的事情,需要做一百次,也就不是简单的事情了。
TeaDSL 的解决之道
TeaDSL 是由阿里云开放平台 SDK 团队主导设计的一门领域特定语言。主要用于解决如下问题:
- 通过一门中间语言,可以支持不同风格的网关。即使网关下的 OpenAPI 风格各异,也能一致地表达到。
- 可以通过翻译的能力,实现对不同编程语言的代码生成。也就是可以基于统一的中间表达,生成多语言的 SDK。
- 基于中间表达,我们可以将一组 OpenAPI 视为一个 library,因此可以在这个基础上实现 OpenAPI 接口的 Code Sample 编写。进而实现多语言的 Code Sample 统一生成。
因此 TeaDSL 的核心能力就是通过一种中间语法来描述 OpenAPI,提供类似编程语言的能力,来将 OpenAPI、SDK、Code Sample 等场景及语言有机地结合在一起。
在没有 TeaDSL 之前,对于不同的网关,我们要为它制定独立的工作流程,即从 OpenAPI 定义到不同语言的 SDK 生成,是独特的。换一个新的网关风格,就要重新实现这套流程。
正在上传…重新上传取消
图 5 M 个网关都要支持 N 种编程语言,整个工作量是 M * N 的关系
而具有 TeaDSL 后,我们则形成一个中间层。可以将原来的工作收敛起来,我们仅需要关注不同的网关到 TeaDSL 的转换工作,以及 TeaDSL 到各个编程语言的生成工作。
图 6 经过中间层的隔离,整个工作量变为 M + N 的关系
也就是说,TeaDSL 是在做一件 M * N 到 M + N 的工作。当网关越多,支持的编程语言越多,收益则越大。
一旦这个中间层建立起来,整个 OpenAPI 的应用形式都可以基于它来构建。比如,编写一个 OpenAPI 的 Code Sample,Test Case 等。
接下来简单介绍 TeaDSL 是如何实现支持任意风格的网关和多种编程语言的。
如何支持任意风格的网关
对于不同的 API 网关,或者不同产品的 OpenAPI 而言,它们之间的风格可能都千差万别,因此在很大的程度上,每种风格的 OpenAPI 都有它自己的元数据定义格式。为了减少网关、风格带来的差异化,业界主要推动的方式是尽量采用标准的定义格式。比如 Swagger 就是其中的佼佼者,它依托于 OpenAPI Specification ,以 RESTful 风格的 OpenAPI 作为基准,形成了一套业界标准。
但这个世界就是这样不完美,我们现有的大量 OpenAPI 并不是 RESTful 风格的。这导致很多的产品现存的 OpenAPI 在文档、SDK等场景下,无法使用上 Swagger 这样强大的生态工具链。
为了解决这些问题,我们需要进行两步操作:
- 设立一套新的标准,来包容不同风格的 OpenAPI
- 以这套新的标准,来建设生态工具链
如果完成这两个步骤,那么现实世界上的每一个 OpenAPI,RESTful 或者非 RESTful 的,不需要做任何迁移,也能具有强大的工具链支持。
新标准的设计
通过我们的研究发现,无论 OpenAPI 的参数是如何组成的,传输是 JSON,还是 XML,乃至自定义协议,OpenAPI 都是基于 HTTP 协议栈进行提供的。也就是说,万变不离其宗的是 HTTP 协议本身。因此我们确立的基本模型是这样的:
{protocol: string, // http or httpsport: number, // tcp porthost: string, // domainrequest: {method: string, // http methodpathname: string, // path namequery: map[string]string, // query stringheaders: map[string]string, // request headersbody: readable // request body},response: {statusCode: number, // http methodstatusMessage: string, // path nameheaders: map[string]string, // response headersbody: readable // response body},
}
对于不同风格的 OpenAPI 而言,就像不同风格的建筑,它们的建筑材料都几乎相同,只是施工手法,组合形式不一样而已。我们看到的 OpenAPI 风格差异,实质则是序列化过程不同而带来的不同。我们序列化过程和数据模型分离,将用户更直观的数据结构提取出来。
比如从用户角度出发,一个数据模型是更直观的事物:
model User {username: string,age: number
}
在不同的网关下,它的传输形式可能是 JSON,也可能是 XML,但最终都是 readable,也就是可读的字节流。
toJSON(user: User): string
toXML(user: User): string
最终的结果就是:
__request.body = toJSON(user);
__request.body = toXML(user);
更进一步的过程是,我们会将一个 OpenAPI 的请求/响应包装为一个类似于编程代码的方法:
api getUser(username: string): User {__request.method = 'GET';__request.pathname = `/users/${username}`;__request.headers = {host = 'hostname',};
} returns {var body = readAsJSON(__response.body);return body;
}
尽管上面的代码不能实际运行,但大致也看出来我们包容不同的网关、风格的办法如下:
- 以 request / response 也就是 HTTP 协议作为核心模型
- 通过引入一些方法,如 toJSON / toXML / readAsJSON 等方法来分离数据结构和序列化过程
- 将整个过程包装成方法
这些方法在不同的编程语言下具有不同的实现,但我们只要定义好统一的签名,就能确保一致性:
function toXML(data: $Model): string;
function toJSON(data: $Model): string;
以上就是 TeaDSL 如何实现支持任意网关的方案。整个过程相对抽象,网关间的那些具有差异化的风格,统统交给这些方法去实现,留下来的就只有数据结构。
如何支持不同的编程语言
如果只是能通过一种描述方式来描述不同的 OpenAPI 调用过程,只是完成了一半的工作。另一半的工作是如何将这种描述语言落地到不同的编程语言下。在过去,我们支持不同的编程语言,主要是基于模版的形式来生成不同语言的实际代码。但这对我们来说仍然还有一些不足之处:
- 模版的生成方式相对生硬,实现起来容易,但维护起来不那么灵活
- 生成出来的代码容易带来命名冲突,语法错误等
从上面的形式也看到,这个方案,被我们设计成了一种 DSL 代码。因此它是具有自己的词法、语法、语义规则的,在生成目标编程语言代码之前,会有一套自身的校验。DSL 的这些能力是模版所不具备的。
可能对于别的场合,采用 DSL 的形式并不多见。但对于前端工程师而言,这些年已经见的较多了:CoffeeScript、Babel、JSX、TypeScript 等等。为此我们参考了诸多编程语言的设计,最终形成了自己的一套语法。并借鉴编译器领域的转译方式,因此我们可以在模型一致的情况,生成到各种不同的编程语言下。
整个 TeaDSL 的处理流程如下:
最终我们支持多种编程语言的场景主要有3个:
- 基本的多种语言的 SDK
- OpenAPI 相关的多种语言的 Code Sample
- OpenAPI 相关的多种语言的 Test Case
通过中间语言的强校验,生成到多种目标场景,可以解决编程语言支持不全面的问题。同时也大幅节约 OpenAPI 维护者的精力成本,不需要反复手工地编写不同编程语言下的 Code Sample。随着对不同编程语言的支持逐步完善,这些中间 TeaDSL 代码不需要任何操作,即可自动支持到新的编程语言下。
总结
TeaDSL 的主要能力是支持到不同风格的 OpenAPI,同时支持多语言的 SDK、Code Sample 目标生成。最终的目的仍然是打通从 OpenAPI 定义到文档、到 SDK、CLI 等 OpenAPI 使用场景下的一致性。提供给用户更统一、专业、一致的使用体验。同时也大幅降低 OpenAPI 提供者用来支持用户的成本,通过自动化的方式,节省精力的同时,还减少人为参与时导致的错误。
目前 TeaDSL 在阿里云的一些 SDK 上已经有所应用,如:https://github.com/aliyun/aliyun-ccp。阿里云开放平台在持续努力提升它的整个工具支持生态,以期望能建成比 Swagger 更适配的生态体系。
原文链接
本文为云栖社区原创内容,未经允许不得转载。
TeaDSL:支持任意 OpenAPI 网关的多语言 SDK 方案相关推荐
- 如何实现 OpenAPI 多语言 SDK 开发?
简介:由于每个网关所对应的后端情况不同,因此没有一套元数据可以适用于所有的网关.阿里云通过重新定义一门 DSL 语言 -- Darabonba 来支持不同风格的 OpenAPI,同时支持多语言的 SD ...
- php生成excel范例,支持任意行列
因为项目多语言化,需要做一个语言包和excel快速转换的功能,下面代码需要PHPExcel插件支持 <?php /** * PHPEXCEL生成excel文件 * @author:fir ...
- 扩展activiti 支持任意属性扩展
本文主要讲解如何扩展activiti,使其支持任意属性配置. 先来看下效果 这个流程的分支二这个人员设置,实际存放xml格式如下: <userTask id="Activity_03o ...
- mac邮件过滤器SpamSieve,支持任意类型的任意数量的电子邮件帐户
SpamSieve for mac是适用于Mac系统的一款邮件过滤器.spamsieve mac支持任意类型的任意数量的电子邮件帐户,可以通过各种标准可靠地识别哪些消息不是垃圾邮件,了解您的合法邮件是 ...
- 支持任意排序的分页存储过程
从网上找了一个分页存储过程,在使用的过程中出现对非主键排序查询时,查不到数据,根据sql2005 的特点修改了其bug,已经添加性能测试(2008-10-27). 存储过程 IF OBJECT_ID( ...
- go语言 不支持动态加载_动态语言支持
go语言 不支持动态加载 本文是我们名为" 高级Java "的学院课程的一部分. 本课程旨在帮助您最有效地使用Java. 它讨论了高级主题,包括对象创建,并发,序列化,反射等. 它 ...
- 提升普适性,阿里云官方SDK发布支持Go语言SDK
摘要: 日前,阿里云官方SDK发布支持新语言--Go 语言SDK,意味着90%以上产品可以随时生成并发布Go SDK,给Go语言的开发者使用. 此次阿里云发布支持Go SDK的新功能,可以让Go语言开 ...
- python工具方法 10 h5py批量写入文件、读取文件,支持任意维度的数据
1.创建引入库并创建h5文件 import h5py import numpy as npfile_name='data.h5' h5f=h5py.File(file_name) 2.批量写入数据的方 ...
- paddlepaddle 27 支持任意维度数据的梯度平衡机制GHM Loss的实现(支持ignore_index、class_weight,支持反向传播训练,支持多分类)
GHM Loss是Focal loss的升级版,它对难样本进行了深入的分析,认为并非所有的难样本都值得关注.有一些难样本属于标签错误的,不应该进行加强.GHM Loss根据loss的梯度模长(1-so ...
最新文章
- 谈谈 Tomcat 请求处理流程
- android开发控件水波纹,Android实现水波纹控件的方法
- 五、规则组织的衍生组织——纬山形组织数学模型的建立
- React开发(218):dva注意对应
- 咸鸭蛋吃了对身体有什么好处?
- Python爬取网页源码,图片和文字到本地
- Windows游戏编程大师技巧笔记(一些基础)
- 进程间通信——系统调用setjmp()与longjmp()
- 微信小程序/js上传图片值腾讯云cos
- 计算机组成原理课程要求及目的,计算机组成原理-教学大纲
- mate7 android升级包下载,华为mate7 刷机包
- hivesql:行列转换
- matlab的四个取整函数!
- Android工具 - 随机测试(猴子)
- Mac双系统Win10系统安装MySQL的坑
- 我们认为2是第一个素数,3是第二个素数,5是第三个素数,依次类推。现在,给定两个整数n和m,0<n<=m<=200,你的程序要计算第n个素数到第m个素数之间所有的素数的和,包括第n个素数和第m个素数
- ecshop首页幻灯片大小设置
- SD/TF卡驱动(二)--------SD卡程序初始化流程以及读写
- 顺序表ADT模板设计及简单应用:将顺序表中前 m 个元素和后 n 个元素进行互换
- ipadpro怎么分屏_2020款iPad Pro开箱测评:下一个十年,打开AR新世界的大门
热门文章
- python常用模块用法_python常用模块(一)
- mysql-5.7.24初始化数据库_MySQL5.7.28 初始化数据库
- 云教版认识计算机说课,【教学设计】第1册第1课《认识电脑交朋友》
- 天正双击墙体不能编辑_今日设计分享:CAD常用快捷键、Ps快捷键大全、天正快捷键总结!...
- 深度linux缺点,原来国产深度系统有这些“缺陷”,难怪只有少数人在使用!
- python图片横向合并_[宜配屋]听图阁
- 武大计算机几天出录取结果,录取大概要几天 多久录取结果出来
- 安徽工业大学计算机考研历年分数线,安徽工业大学历年考研分数线汇总[2012-2021]...
- cstring越界_char*、WCHAR*、vc8中的CString
- 从优青到杰青:优秀青年科技人才成长典型特征