如何实现 OpenAPI 多语言 SDK 开发?
如今 OpenAPI 已經(jīng)成為完成系統(tǒng)之間集成的重要橋梁,OpenAPI 的可用性以及用戶在使用時(shí)的體驗(yàn)就變得越來(lái)越重要,阿里云前架構(gòu)師曾說(shuō)過(guò):"阿里云的本質(zhì)是一家賣 API 的公司。API 有沒有做好,是關(guān)乎生死的大事"。但是從日常來(lái)自用戶的反饋中我們總結(jié)了以下比較通用的幾點(diǎn) OpenAPI 體驗(yàn)問(wèn)題:
- 云產(chǎn)品 OpenAPI 沒有提供 SDK 或者 SDK 語(yǔ)言不全;
- 部分云產(chǎn)品的 SDK 使用風(fēng)格差異過(guò)大,導(dǎo)致使用成本增加;
- API 文檔缺失或者不夠清晰,不具備指導(dǎo)意義;
- 沒有場(chǎng)景化 Code Sample 或提供 CodeSample 無(wú)法運(yùn)行。
多語(yǔ)言 SDK 生成
說(shuō)起生成多語(yǔ)言 SDK,大家第一時(shí)間想起的一定是當(dāng)前業(yè)界內(nèi)生成多語(yǔ)言 SDK 的通用方案——Swagger,開發(fā)者通過(guò) Swagger 定義的 OpenAPI 標(biāo)準(zhǔn)并配合模板的方式來(lái)生成多語(yǔ)言 SDK。不過(guò)問(wèn)題并沒有因此而得到完美的解決。首先模版的生成方式相對(duì)生硬,雖然實(shí)現(xiàn)起來(lái)容易,但維護(hù)起來(lái)卻不那么靈活;其次,大量 OpenAPI 并不是 RESTful 風(fēng)格的,這就導(dǎo)致很多產(chǎn)品現(xiàn)存的 OpenAPI 在文檔、SDK 等場(chǎng)景下,無(wú)法使用上 Swagger 這樣強(qiáng)大的生態(tài)工具鏈。既然無(wú)法沿用 Swagger 規(guī)范元數(shù)據(jù)的方法來(lái)解決這個(gè)問(wèn)題,我們就需要對(duì)我們的工作重新進(jìn)行抽象。在筆者看來(lái),之所以沒有一套元數(shù)據(jù)可以適用于所有的網(wǎng)關(guān)主要還是因?yàn)槊總€(gè)網(wǎng)關(guān)所對(duì)應(yīng)的后端情況不同,就像機(jī)器語(yǔ)言或者匯編語(yǔ)言會(huì)因?yàn)榧軜?gòu)的不同而有所不同,但是其本質(zhì)還是描述如何通過(guò)操作寄存器、內(nèi)存里的數(shù)據(jù)來(lái)完成一個(gè)程序,高級(jí)語(yǔ)言就是通過(guò) AST 兼容了各平臺(tái)的這些不同最后解決了這些問(wèn)題。而對(duì)于 OpenAPI 來(lái)說(shuō)也是同樣的道理,所以我們通過(guò)重新定義一門 DSL 語(yǔ)言 Darabonba 來(lái)描述各種各樣的 OpenAPI。
通過(guò) Darabonba 對(duì) OpenAPI 進(jìn)行描述,其本質(zhì)就是統(tǒng)一了元數(shù)據(jù),只是這個(gè)元數(shù)據(jù)并不是 JSON 或者 Yaml 這樣的方式來(lái)描述的,而是通過(guò) DSL 代碼來(lái)描述。Darabonba 的編譯器則會(huì)將 Darabonba 的 DSL 代碼轉(zhuǎn)化為 AST,通過(guò) OpenAPI 描述轉(zhuǎn)化而來(lái)的 AST 不僅包含了 OpenAPI 的信息,而且還包含整個(gè) OpenAPI 的流程性描述,所以我們只需要通過(guò) AST 開發(fā)對(duì)應(yīng)的各語(yǔ)言SDK就可以生成多語(yǔ)言的 SDK了。Darabonba 具體的設(shè)計(jì)思路和理念可參考文章:Darabonba:支持任意 OpenAPI 網(wǎng)關(guān)的多語(yǔ)言 SDK 方案,這里就不再贅述。
模塊化設(shè)計(jì)
在通過(guò)元數(shù)據(jù)向生成 SDK 的過(guò)程中,僅僅通過(guò)對(duì) OpenAPI 的數(shù)據(jù)模型和請(qǐng)求/響應(yīng)描述是不夠的,還需要各種參數(shù)處理,簽名生成,文件上傳,流操作等各種復(fù)雜的方法,以往通過(guò)模板生成 SDK 的時(shí)會(huì)選擇維護(hù)一個(gè)各語(yǔ)言的核心模塊來(lái)封裝這些方法,但是隨著支持的 OpenAPI 越來(lái)越多核心庫(kù)中的方法也是越來(lái)越多,就會(huì)產(chǎn)生以下的問(wèn)題:
- 客戶使用或者開發(fā)者接入核心庫(kù)的 SDK 開發(fā)者來(lái)說(shuō)成本會(huì)越來(lái)越大;
- 核心庫(kù)的維護(hù)人員的維護(hù)成本也會(huì)越來(lái)越高,隨著方法越來(lái)越多也需要不斷的對(duì)核心庫(kù)進(jìn)行重構(gòu),遇到不兼容性改動(dòng)的可能性也會(huì)越來(lái)越高;
- 所有方法雜糅在一個(gè)核心庫(kù)中,在修改時(shí)容易牽一發(fā)動(dòng)全身,需要大量的測(cè)試用例保障。
在通過(guò) Darabonba 生成的 SDK 時(shí)也會(huì)遇到同樣的問(wèn)題,Darabonba 作為一門 DSL 語(yǔ)言主要能力在于描述 OpenAPI ,為了保障生成的 SDK 具備完整的功能同樣需要很多實(shí)現(xiàn)很多核心方法,而在總結(jié)以往維護(hù)核心庫(kù)的中遇到的問(wèn)題以后,我們選擇了現(xiàn)在在高級(jí)語(yǔ)言中非常常見的模塊化開發(fā)理念,并提供了相應(yīng)的命令行工具 Darabonba CLI 和 Darabonba 模塊倉(cāng)庫(kù)。
接口模塊
Darabonba 其核心能力是描述 OpenAPI,缺少?gòu)?fù)雜邏輯實(shí)現(xiàn)的能力,為了彌補(bǔ)這個(gè)能力 Darabonba 設(shè)計(jì)了接口模塊的概念。與 Java 中的 interface 接口類型定義類似,Darabonba 的接口模塊即是只在 Darabonba 編寫的DSL 代碼中只定義方法體的集合而并不實(shí)現(xiàn)其具體邏輯,真正的邏輯則是由各語(yǔ)言分別實(shí)現(xiàn)。例如 Darabonba 中常用的 Console 模塊:
/*** Console val with log level into stdout* @param val the printing string* @return void* @example \[LOG\] tea console example*/ static function log(val: string): void;我們只需要在模塊中申明模塊包含 log 方法并描述它的出參入?yún)⒓纯?#xff0c;而各語(yǔ)言則通過(guò)自身語(yǔ)言的特性來(lái)實(shí)現(xiàn)該方法即可,其具體實(shí)現(xiàn)可參考 Console 模塊源碼。在編寫好生成接口模塊以后可以通過(guò) Darabonba 提供的 Darabonba CLI 執(zhí)行 dara publish 將模塊發(fā)布到 Darabonba 模塊倉(cāng)庫(kù),就可以在 Darabonba 代碼中使用了。下面就是我們通過(guò)引入 Console 模塊來(lái)打印字符串的一段代碼:
import Console;static async function main(args: [ string ]) throws : void {Console.log("hello world!"); }通過(guò)接口模塊的設(shè)計(jì)理念將以往核心庫(kù)中的方法根據(jù)功能拆分成一個(gè)個(gè)包含了特定功能的基礎(chǔ)模塊,不僅使得生成的 SDK 更好用邏輯更清晰,同時(shí)也做到了足夠的抽象避免很多在生成 SDK 過(guò)程中重復(fù)造輪子的工作。目前 Darabonba 官方提供了包含了常用方法的 Util 模塊、文件上傳所使用的 FileForm 以及 XML 模塊等,同時(shí)開發(fā)者也可以編寫與自己業(yè)務(wù)邏輯相關(guān)的接口模塊并發(fā)布到 Darabonba 模塊倉(cāng)庫(kù)。
OpenAPI 模塊
在 Darabonba 的模塊化設(shè)計(jì)中不止有接口模塊,事實(shí)上每一個(gè) Darabonba 的項(xiàng)目都是一個(gè)模塊,所以基于一組 OpenAPI 描述編寫的 Darabonba 代碼就是一個(gè) OpenAPI 模塊。開發(fā)者在完成了 OpenAPI 描述的 Darabonba 代碼編寫以后,同樣可以通過(guò) Darabonba CLI 將描述 OpenAPI 的 Darabonba 模塊發(fā)布到模塊倉(cāng)庫(kù)中,這樣使用 SDK 的用戶就可以通過(guò)模塊的詳情頁(yè)面查看 SDK 中包含的方法及各語(yǔ)言 SDK 的安裝說(shuō)明等信息了。
基于一組 OpenAPI 發(fā)布的 Darabonba 模塊不僅可以幫助用戶更好的了解這組 OpenAPI,更可以在這個(gè)基礎(chǔ)上實(shí)現(xiàn) OpenAPI 接口的 Code Sample 編寫,進(jìn)而實(shí)現(xiàn)多語(yǔ)言的 Code Sample 統(tǒng)一生成。
Code Sample 自動(dòng)生成
可以說(shuō)對(duì)于簡(jiǎn)單的 API 調(diào)用普通的 API 文檔就足夠了,但是隨著現(xiàn)在 OpenAPI 在系統(tǒng)與系統(tǒng)集成之間使用的越來(lái)越廣泛,其復(fù)雜度也隨之提高,以往單純使用 API 文檔的方式已經(jīng)不足以讓客戶順利的使用 OpenAPI 了。從阿里云目前的工單情況來(lái)看,SDK 相關(guān)的客戶咨詢至少有一半是因?yàn)闆]有 Code Sample 造成的,其中更是有1/4的客戶是直接要求為 SDK 提供 Code Sample。
這種情況下,能夠提供給用戶可運(yùn)行、可調(diào)試的 Code Sample 示例就成了文檔中必不可少的一部分,但是如何能夠編寫全語(yǔ)言的 Code Sample 并且保障其可運(yùn)行,卻是一個(gè)極大的問(wèn)題。如果通過(guò)人力來(lái)維護(hù),很容易就出現(xiàn)語(yǔ)言不全,或是編寫的代碼沒有維護(hù)的問(wèn)題,阿里云中遇到最多的問(wèn)題就是 OpenAPI 在迭代,而 Code Sample 卻忘記迭代了造成了提供出去的 Code Sample 無(wú)法使用從而被用戶詬病。
通過(guò)引用模塊倉(cāng)庫(kù)中 Darabonba 模塊編寫的 CodeSample 則可以避免這樣的問(wèn)題,首先多語(yǔ)言的自動(dòng)生成,節(jié)約了大量的維護(hù)成本,而且風(fēng)格統(tǒng)一利于用戶理解;同時(shí) Darabonba 編譯時(shí)采用類型的強(qiáng)校驗(yàn),一旦 OpenAPI 的參數(shù)或者返回結(jié)果出現(xiàn)了不兼容的更新,CodeSample 則會(huì)生成失敗從而通知到開發(fā)者更新相關(guān)示例來(lái)解決這個(gè)問(wèn)題。下面是阿里云語(yǔ)音服務(wù) SDK 相關(guān)的 CodeSample 示例,大家也可以點(diǎn)擊示例鏈接嘗試生成:
import Dyvmsapi; import RPC; import Console;/*** 使用AK&SK初始化賬號(hào)Client* @param accessKeyId* @param accessKeySecret* @param regionId* @return Client* @throws Exception*/ static function createClient (accessKeyId : string , accessKeySecret : string) throws : Dyvmsapi{var config = new RPC.Config{};// 您的AccessKey IDconfig.accessKeyId = accessKeyId;// 您的可用區(qū)IDconfig.accessKeySecret = accessKeySecret;return new Dyvmsapi(config); }/*** @param args* @throws Exception*/ static async function main(args: [string]) throws : void {var client = createClient("accessKeyId","accessKeySecret");var request = new Dyvmsapi.QueryCallDetailByCallIdRequest{// 通話的唯一識(shí)別ID。callId = "100625930001^10019107xx",// 產(chǎn)品ID。// 11000000300006:語(yǔ)音通知。// 11010000138001:語(yǔ)音驗(yàn)證碼。// 11000000300005:語(yǔ)音IVR。// 11000000300004:語(yǔ)音雙呼。// 11000000300009:語(yǔ)音SIP。// 11030000180001:智能外呼。prodId = 11000000300004L,// 指定通話發(fā)生的時(shí)間,格式為Unix時(shí)間戳,單位毫秒。會(huì)查詢這個(gè)時(shí)間點(diǎn)對(duì)應(yīng)的一整天的記錄。queryDate = 1577255564};var response = client.queryCallDetailByCallId(request);Console.log(response.code); }Test Cases 自動(dòng)生成
在 OpenAPI 公布上線以后,如何能夠保障 OpenAPI 持續(xù)可用就是一個(gè)非常重要的問(wèn)題,如果沒有一個(gè)保障機(jī)制,很可能會(huì)出現(xiàn) OpenAPI 出了問(wèn)題就無(wú)法及時(shí)發(fā)現(xiàn),客戶的投訴也就隨之而來(lái)。而且 OpenAPI 和 SDK 也會(huì)遇到更新升級(jí)等情況,如何能保障這些更新升級(jí)不會(huì)給正在使用 OpenAPI 的客戶造成問(wèn)題也是 OpenAPI 提供方遇到的一個(gè)非常大的挑戰(zhàn)。為了解決這些挑戰(zhàn), 就需要 OpenAPI 提供方編寫 Test Cases 作為日常的持續(xù)集成來(lái)檢驗(yàn) OpenAPI 的可用性,但是目前多語(yǔ)言的 SDK 的 Test Cases 大多存在以下的問(wèn)題:
- 需要大量的人力去維護(hù) Test Cases ,而且無(wú)法保障所有語(yǔ)言的 SDK 都擁有 Test Cases;
- OpenAPI 的 Test Cases 少且更新頻率低,造成了對(duì) OpenAPI 的覆蓋面低而無(wú)法起到有效的保障作用;
- 各語(yǔ)言 SDK 的由各語(yǔ)言的開發(fā)同學(xué)分別維護(hù),所以用例不同步導(dǎo)致不同語(yǔ)言之間的測(cè)試結(jié)果有所差異。
而Darabonba 的多語(yǔ)言生成能力則可以解決以上所有問(wèn)題,只需要引用 SDK 在模塊倉(cāng)庫(kù)中對(duì)應(yīng)的 Darabonba 模塊與 Darabonba 官方提供的斷言模塊 Assert 模塊編寫對(duì)應(yīng)的 Darabonba Test Cases 即可為各語(yǔ)言 SDK 生成其對(duì)應(yīng)的 Test Cases。通過(guò) Darabonba 自動(dòng)化生成 Test Cases 不僅可以解決人力不足 Test Cases 很難覆蓋各語(yǔ)言 SDK 的情況,而且生成的各語(yǔ)言 Test Cases 標(biāo)準(zhǔn)一致,也可以解決各語(yǔ)言 Test Cases用例不同步造成的測(cè)試差異問(wèn)題。下面是一段通過(guò) Darabonba 編寫的測(cè)試用例:
import Assert; import Dyvmsapi; import RPC;static function createClient (accessKeyId : string , accessKeySecret : string) throws : Dyvmsapi{var config = new RPC.Config{};config.accessKeyId = accessKeyId;config.accessKeySecret = accessKeySecret;return new Dyvmsapi(config); }static async function TestNumberEqual() throws : void { var client = createClient("accessKeyId","accessKeySecret");var request = new Dyvmsapi.QueryCallDetailByCallIdRequest{callId = "100625930001^10019107xx",prodId = 11000000300004L,queryDate = 1577255564};var response = client.queryCallDetailByCallId(request);Assert.equal(response.code, 'OK', 'queryCallDetailByCallId is failed!'); }Darabonba 的主要能力是支持到不同風(fēng)格的 OpenAPI,同時(shí)支持多語(yǔ)言的 SDK、Code Sample 目標(biāo)生成。最終的目的仍然是打通從 OpenAPI 定義到文檔、到 SDK、CLI 等 OpenAPI 使用場(chǎng)景下的一致性。提供給用戶更統(tǒng)一、專業(yè)、一致的使用體驗(yàn)。同時(shí)也大幅降低 OpenAPI 提供者用來(lái)支持用戶的成本,通過(guò)自動(dòng)化的方式,節(jié)省精力的同時(shí),還可減少人為參與時(shí)導(dǎo)致的錯(cuò)誤。
參與貢獻(xiàn)
Darabonba 的目標(biāo)是讓用戶得到極致的 OpenAPI 體驗(yàn),所以我們也需要更多的人參與到我們的開源項(xiàng)目來(lái),大家可以按以前的方式參與 Darabonba 的貢獻(xiàn):
- 參與其他語(yǔ)言生成器的生成,目前 Darabonba 只支持了比較常用的六門語(yǔ)言,還需要更多生成器的支持。
- 編寫更多底層工具模塊,使 Darabonba 能夠生成更便捷的 SDK。
- 參與 Darabonba 編譯器及 CLI 工具的建設(shè)中來(lái)。
- 編寫更多 OpenAPI 元數(shù)據(jù)轉(zhuǎn)換到 Darabonba 的工具。
相關(guān)閱讀
[1]Darabonba 上手文檔
https://github.com/aliyun/darabonba#%E6%96%87%E6%A1%A3
[2]Darabonba CodeSample 示例
https://darabonba.api.aliyun.com/tutorial/demos
[3]Darabonba:支持任意 OpenAPI 網(wǎng)關(guān)的多語(yǔ)言 SDK 方案
原文鏈接:https://developer.aliyun.com/article/771250?
版權(quán)聲明:本文內(nèi)容由阿里云實(shí)名注冊(cè)用戶自發(fā)貢獻(xiàn),版權(quán)歸原作者所有,阿里云開發(fā)者社區(qū)不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。具體規(guī)則請(qǐng)查看《阿里云開發(fā)者社區(qū)用戶服務(wù)協(xié)議》和《阿里云開發(fā)者社區(qū)知識(shí)產(chǎn)權(quán)保護(hù)指引》。如果您發(fā)現(xiàn)本社區(qū)中有涉嫌抄襲的內(nèi)容,填寫侵權(quán)投訴表單進(jìn)行舉報(bào),一經(jīng)查實(shí),本社區(qū)將立刻刪除涉嫌侵權(quán)內(nèi)容。總結(jié)
以上是生活随笔為你收集整理的如何实现 OpenAPI 多语言 SDK 开发?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 一篇文章教会你使用html+css3制作
- 下一篇: NoSQL和SQL怎么选用?