作為一個雲原生的開發者,你會最關注哪方面的開發體驗?在你的應用中與雲上的資源進行互動肯定是你非常在意的吧,不管是往Service Bus中傳送一條訊息,亦或是為更大的運算需求建立新的虛擬機器。你可以利用雲平臺的SDK,比如Azure SDK來完成所有這些操作,那麼Azure SDK是如何寫出來的呢?一個雲平臺的SDK和一個傳統的SDK有何區別?
傳統SDK和雲平臺SDK之間的不同
傳統SDK, 比如說.NET SDK或者JAVA SDK,都是.NET執行時(.NET CLR)或者JAVA執行時(JVM)的程式設計介面,他們之間的“通訊協議”是在程式內的,基於二進位制的。
雲平臺SDK通常基於OpenAPI定義。OpenAPI更像是一個跨程式的基於RESTFul HTTP APIs的通訊協議,OpenAPI雲端計算的世界中無處不在,但是OpenAPI有其自己的侷限性。
利用OpenAPI和Azure進行互動時候會遇到的問題
OpenAPI是一個REST API Service的介面定義,對於任何一個程式語言來說,他都不是一個開箱即用的解決方案。當一個開發者想要開始使用OpenAPI, 他通常會遇到下面的一些問題:
- 異常處理
- 長時間執行操作的處理
- 分頁操作處理
- HTTP Client生命週期管理
為這些處理構建健壯的程式碼並不是一件容易的事情。這種情況下,引入SDK就變成了一種很自然地選擇。
微軟是如何從OpenAPI中生成Azure SDK的
Azure SDK的設計遵從了通用SDK庫設計指導,這份指導綱要確保了在不同Azure Service之間一致的SDK使用體驗,從2022年3月31號開始,我們對不符合指導綱要版本的SDK庫開始了逐步淘汰。
為一個新的Azure Service建立SDK,Azure SDK團隊緊密合作,常見的工作步驟如下:
- Azure Service團隊定義好OpenAPI說明(Swagger file),並且在REST API specification repository起一個PR。
- Azure SDK 團隊會稽核新的OpenAPI說明,確保裡面沒有破壞性變更,語法錯誤等等。
- Azure SDK 團隊利用AutoRest從OpenAPI說明當中生成客戶端庫。AutoRest是微軟建立的一個開源客戶端庫生成工具來訪問Restful web services. AutoRest利用不同語言的擴充來為不同程式語言生成Restful web service的客戶端庫。
- 我們會稽核生成出來的客戶端庫,並起一個PR到相應語言SDK的Github repository. 我們有一個非常棒的內部工程平臺對這些客戶端庫進行測試,以確保我們不會引入任何regression issue。這些測試包括自動生成的測試和手寫測試,但是在未來我們會更多的依賴自動生成的測試用例。
- 一旦所有檢查都通過了,這個新生成的客戶端庫就會被合併到相應語言的SDK Github Repository。
- 在客戶端庫被合併到相應語言的SDK Github repository之後,相應的持續整合和部署管線就會被觸發,如果一切無誤,新的客戶端庫就會被髮布到相應語言的包管理器,如nuget, npm等等。
- 所有SDK相關文件,樣例程式碼也會陸續得到更新。
AutoRest是整個客戶端庫生成過程當中的關鍵。AutoRest知道常見模式的REST API呼叫,並在客戶端庫中將這些呼叫暴露成對於開發者友好的程式設計介面。比如說,長時間執行的操作(Long-running operation, LRO)以及一些資源建立,刪除等無法立即知道操作結果的REST API呼叫。這些情況下,伺服器會返回一個201(Created)或者202(Accepted)狀態碼,並附帶一個連結來持續監測請求的完成狀態。這個操作行為對於直接的RESTFul API呼叫是合理的,但是從程式語言的角度來看這是有問題的,這種操作應該被轉變成一個帶回撥函式的非同步操作,回撥函式允許開發者為LRO操作的成功或失敗編寫相應程式碼。OpenAPI, 很不幸的,沒有這種非同步語法上的支援。為了能夠支援這種操作,微軟定義了一系列AutoRest OpenAPI擴充來豐富OpenAPI的語法。
現在讓我們回到之前的LRO場景。我們可以在OpenAPI中定義一個x-ms-long-running-operation。比如說,下面的定義是一個建立/更新Azure VM的OpenAPI定義(完整定義可在這裡找到)
"/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Compute/virtualMachines/{vmName}": {
"put": {
"tags": [
"VirtualMachines"
],
"operationId": "VirtualMachines_CreateOrUpdate",
"description": "The operation to create or update a virtual machine. Please note some properties can be set only during virtual machine creation.",
"parameters": [
{
"name": "resourceGroupName",
"in": "path",
"required": true,
"type": "string",
"description": "The name of the resource group."
},
{
"name": "vmName",
"in": "path",
"required": true,
"type": "string",
"description": "The name of the virtual machine."
},
{
"name": "parameters",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/VirtualMachine"
},
"description": "Parameters supplied to the Create Virtual Machine operation."
},
{
"$ref": "#/parameters/ApiVersionParameter"
},
{
"$ref": "#/parameters/SubscriptionIdParameter"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/VirtualMachine"
}
},
"201": {
"description": "Created",
"schema": {
"$ref": "#/definitions/VirtualMachine"
}
},
"default": {
"description": "Error response describing why the operation failed.",
"schema": {
"$ref": "#/definitions/CloudError"
}
}
},
"x-ms-long-running-operation": true
}
}
有了上面的OpenAPI定義,我們生成的客戶端庫中的BeginCreateOrUpdate方法呼叫就變成了下面的樣子,以Go語言為例(完整程式碼可在這裡找到)
pollerResponse, err := vmClient.BeginCreateOrUpdate(ctx, resourceGroupName, vmName, parameters, nil)
if err != nil {
return nil, err
}
resp, err := pollerResponse.PollUntilDone(ctx, 10*time.Second)
if err != nil {
return nil, err
}
}
上述程式碼中的Poller類來自於Azure Core專案。Azure Core提供了整個Azure SDK的基礎架構,比如說HTTP Client的生命週期管理,異常處理。利用Azure Core, 我們就可以在OpenAPI中定義更多的擴充,並將這些擴充轉變成更加開發者友好的客戶端庫語法,常見的OpenAPI擴充有:
- X-ms-error-response:該擴充可以確定是否把一些http返回狀態碼對映成為一個錯誤
- X-ms-pageable:該擴充可以將返回的list對映成為一個可分頁的結果
更多的擴充,請參見AutoRest Extensions for OpenAPI
我們討論了使用雲SDK的好處以及微軟構建雲SDK的流程,感謝您的閱讀。
長按識別二維碼
關注微軟中國MSDN