TeaDSL:支持任意 OpenAPI 网关的多语言 SDK 方案 Posted 2021-04-21 阿里技术
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 团队主导设计的一门领域特定语言。主要用于解决如下问题:
因此 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 ,
port: number,
host: string ,
request: {
method: string ,
pathname: string ,
query: map [string ]string ,
headers: map [string ]string ,
body: readable
},
response: {
statusCode: number,
statusMessage: string ,
headers: map [string ]string ,
body: readable
},
}
对于不同风格的 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 等等。为此我们参考了诸多编程语言的设计,最终形成了自己的一套语法。并借鉴编译器领域的转译方式,因此我们可以在模型一致的情况,生成到各种不同的编程语言下。
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 方案的主要内容,如果未能解决你的问题,请参考以下文章
使用 GCP API 网关的 Graphql 后端的 OpenAPI 配置?
terraform api 网关与 openapi 规范的集成
gcp api 网关在调用 x-google-backend 之前是不是根据 OpenAPI 规范验证请求正文?
聊聊API网关的作用
基于 Go 语言的 API 网关 Goku-API-Gateway | 软件推介
API网关的作用方案以及如何选择