項目地址:
項目目標:
- 基於 Protobuf-V3 語法維護規範, 便於升級和維護
- 更完整的服務支持, 新服務第一時間提供支持
- 更好用的編程接口
在線文檔:
接口規範:
配置文件
當前用戶的配置文件在 ${HOME}/.qingcloud/config.yaml
, 內容如下:
# QingCloud services configuration
qy_access_key_id: 'ACCESS_KEY_ID'
qy_secret_access_key: 'SECRET_ACCESS_KEY'
host: 'api.qingcloud.com'
port: 443
protocol: 'https'
uri: '/iaas'
connection_retries: 3
json_disable_unknown_fields: false
# Valid log levels are "debug", "info", "warn", "error", and "fatal".
log_level: 'warn'
將 qy_access_key_id
和 qy_secret_access_key
字段替換爲 API密鑰 中的內容.
其中 json_disable_unknown_fields
是新加的變量, 表示在JSON解碼時忽略 proto.Message 遇到未定義成員的錯誤.
快速入門
以下爲 hello.go 的內容:
package main
import (
"fmt"
"log"
"github.com/chai2010/qingcloud-go/config"
pb "github.com/chai2010/qingcloud-go/service"
"github.com/golang/protobuf/jsonpb"
"github.com/golang/protobuf/proto"
)
func main() {
// 初始化 青雲 服務對象
qcService, err := pb.Init(config.MustLoadUserConfig())
if err != nil {
log.Fatal(err)
}
// 返回 NIC 子服務, pek3a 爲 北京3區-A
nicService, err := qcService.Nic("pek3a")
if err != nil {
log.Fatal(err)
}
// 列出所有網卡
reply, err := nicService.DescribeNics(nil)
if err != nil {
log.Fatal(err)
}
// 原始返回的json數據
// nicService.LastResponseBody
// JSON 格式打印
fmt.Println(jsonpbEncode(reply))
}
// pb轉json, 採用原始名稱, 不忽略空值
func jsonpbEncode(m proto.Message) string {
jsonMarshaler := &jsonpb.Marshaler{
OrigName: true,
EnumsAsInts: true,
EmitDefaults: true,
Indent: " ",
}
s, err := jsonMarshaler.MarshalToString(m)
if err != nil {
log.Fatal(err)
}
return s
}
初始化子服務也可以用以下方式:
nicService := pb.NewNicService(config.MustLoadUserConfig(), "pek3a")
運行例子:
go run hello.go
更多例子.
文檔指南
使用青雲SDK一般是以下步驟:
- 用 config 包構造一個配置對象, 裏面含有最重要的 API密鑰, 還包含日誌級別等信息.
- 基於配置對象調用 service 包的
Init
函數構造一個青雲主服務對象qcService
, 其中會根據配置文件設置日誌級別. - 假設有一個 UserData 子服務, 那麼調用
qcService.UserData("pek3a")
方法將返回子服務對象, 其中參數是區域 - 使用子服務對象就可以調用每個子對象的方法了
我們可以查看子服務對應的接口規範, 在 spec.pb/user_data.proto 文件定義 (青雲文檔):
service UserDataService {
rpc UploadUserDataAttachment(UploadUserDataAttachmentInput) returns (UploadUserDataAttachmentOutput);
}
message UploadUserDataAttachmentInput {
bytes attachment_content = 2;
string attachment_name = 1;
}
message UploadUserDataAttachmentOutput {
string action = 1;
int32 ret_code = 2;
string message = 3;
string attachment_id = 4;
}
其中service
關鍵字開頭的表示定義一組子服務, 其中rpc
開頭的表示子服務中每個具體的方法. 方法的輸入參數和返回值分別爲UploadUserDataAttachmentInput
和UploadUserDataAttachmentInput
結構體類型, 它們由後面的message
關鍵字定義.
SDK的代碼生成插件 會生成以下的Go語言代碼:
type UserDataService struct {
// ...
}
func (p *QingCloudService) UserData(zone string) (*UserDataService, error) {
// ...
}
type UploadUserDataAttachmentInput struct {
// ...
}
type UploadUserDataAttachmentOutput struct {
// ...
}
func (p *UserDataService) UploadUserDataAttachment(
in *UploadUserDataAttachmentInput,
) (
*UploadUserDataAttachmentOutput,
error,
) {
// ...
}
規範文件的語法細節可以參考 spec.pb/README.md, proto3 文件語法可以參考 Protobuf 的官方文檔.
與官方文檔的兼容性
- 該 SDK 和 官方 SDK 的 API 保持最大的兼容性
- 即使有不兼容的地方, API 也是非常相似的
假設青雲的REST規範的文檔中有一個名爲 job_id
的輸入參數, 對應 XXXInput
結構體的成員.
官方文檔是根據 json定義的規範, 然後通過一個名爲 snips 的工具加自己定義的 模板 生成的代碼, XXXInput
輸入參數生成的代碼可能類似以下結構:
type XXXInput struct {
JobID *string `json:"job_id" name:"job_id" location:"elements"`
}
而我們的SDK採用Protobuf3標準工具生成的代碼:
type XXXInput struct {
JobId string `protobuf:"bytes,5,opt,name=job_id,json=jobId" json:"job_id,omitempty"`
}
其中有兩個大的差異: 一個是成員名稱不同, 分別爲 JobID
和 JobId
; 另一個爲類型不同, 分別爲 *string
和 string
.
snips 採用和 Protobuf-V2 類似的生成規則, 零值是 nil
, 空值是空字符串, 二者是不等價的. 在 Protobuf3 的生成規則中, 默認將零值和空值等價.