7
0
gaore-common-sdk-go/README.md

206 lines
7.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# gaore-common-sdk-go
### 1.目录架构
```
├── README.md
├── sdk
│   ├── auth `认证类`
│   ├── client.go `客户端主入口类`
│   ├── config.go
│   ├── requests `请求类`
│   ├── responses `响应类`
│   └── utils `工具类`
└── services
└── jedi
```
### 2.引入
```go
go get -u golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk
```
或 Go Module
```go
import "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk"
```
### 3.服务端认证及返回处理
调用 `auth.UnSign` 方法,提供`*http.Request`请求实例,以及`signer.Signer` 签名器(签名器需要包括凭据)
即可完成整个验签过程
这里以`beego`为例 :
```go
package applications
import (
"github.com/astaxie/beego"
"github.com/astaxie/beego/context"
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/auth"
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/auth/credentials"
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/auth/signers"
"golib.gaore.com/GaoreGo/grlogs"
)
func init() {
// 过滤器
beego.InsertFilter("/api/*", beego.BeforeRouter, func(context *context.Context) {
httpRequest := context.Request
err := auth.UnSign(httpRequest, signers.NewAccessKeySigner(&credentials.AccessKeyCredential{
AccessKeyId: "aaaaaa",
AccessKeySecret: "bbbbbb",
AccessKeyFrom: context.Input.Param("access_from"),
}))
if err != nil {
resp := response.NewJsonByDefaultFailed()
resp.Msg = err.Error()
resp.Code = 10086
var (
hasIndent = beego.BConfig.RunMode != beego.PROD
)
context.Output.Status = 500
context.Output.JSON(resp, hasIndent, false)
}
})
}
```
服务端返回的响应体为以下结构的json字符流, `code`,`status`,`msg` 这三个字段*最好*要包含且数据类型要一致 , `data` 部分为业务内容,自行定义
```json
{
"code": 1001,
"msg": "不能为空",
"status": false,
"data": {
...
}
}
```
### 4.sdk编写
在`services`目录下以服务归类新建文件夹, 如`jedi`为短信服务,以 `RpcRequest``BaseResponse` 以基类写好请求子类和响应子类。一个请求接口对应一对请求和响应类。
```go
import "golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk"
const (
HOST = "jedi" // 如果非全域名会自动补全.gaore.com , 如jedi 会自动补全jedi.goare.com, 也可以打全域名 test.uu89.com
VERSION = "2020-08-04"
)
type Client struct {
sdk.Client
}
func NewClientWithAccessKey(accesskey, secrect, source string) (client *Client, err error) {
client = &Client{}
err = client.InitWithAccessKey(accesskey, secrect, source)
return
}
func (c *Client) Test(req *DemoTestRequest) (response *DemoTestResponse, err error) {
response = CreateDemoTestResponse()
err = c.DoAction(req, response)
return
}
```
请求类,对参数用标签解释, 如 `position:"Query" field:"param_1" default:""` 有三个字段 `position` , `field`, `default`
- `position` 为标志该参数为请求体对应的位置, `Query` query参数, `Body` post请求体参数, `Head`请求头参数
- `field` 解释成参数实际名称
- `default` 默认值
```go
type DemoTestRequest struct {
*requests.RpcRequest
Param1 string `position:"Query" field:"param_1" default:"" `
Param2 int `position:"Query" field:"param_2" default:"10086" `
Param3 bool `position:"Query" field:"param_3" default:"false" `
}
```
对应解释成http请求为
```go
GET param_1=111&param_2=10086&param_3=false
```
完整示例:
```go
package jedi
import (
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests"
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses"
)
// 定义请求体
type DemoTestRequest struct {
*requests.RpcRequest
Param1 string `position:"Query" field:"param_1" default:"" `
Param2 int `position:"Query" field:"param_2" default:"10086" `
Param3 bool `position:"Query" field:"param_3" default:"false" `
}
func CreateDemoTestRequest() (req *DemoTestRequest) {
req = &DemoTestRequest{RpcRequest: &requests.RpcRequest{}}
// InitWithApiInfo 初始化请求,有三个参数,域名,版本,和路径
// 域名参数如果非全域名会自动补全.gaore.com , 如jedi 会自动补全jedi.goare.com, 也可以打全域名 test.uu89.com
req.InitWithApiInfo(HOST, VERSION, "/api/sms/Index")
// 定义 请求方法 POST 或 GET
req.Method = requests.GET
return
}
// 定义响应体
type DemoTestResponse struct {
*responses.BaseResponse
Data DemoTestResponseData `json:"data"`
}
type DemoTestResponseData struct {
Account string `json:"account"`
Total int `json:"total"`
}
func CreateDemoTestResponse() *DemoTestResponse {
return &DemoTestResponse{
BaseResponse: &responses.BaseResponse{},
}
}
```
终端调试打开方式, 需要在系统环境变量上加入(三选一):
```
DEBUG=sdk,signer,request
```
### 5.测试用例编写要求
新增或修改 `services/*` 下的接口封装时,**必须**配套可编译的测试,并遵循下列约定(风格可参考 `services/cs/client_test.go``services/game/client_test.go`)。
#### 5.1 单测职责(一条用例里要覆盖什么)
- **请求侧**:构造 `Create*Request`,填入业务参数后调用 `requests.InitParam(req)`,再断言 HTTP 方法、`GetActionName()` 路径、以及 Query/Form 等关键参数是否注入正确。
- **调用侧**:使用本服务 `NewClient()`(或项目约定的构造方式)**真实调用** `Client` 上对应方法,覆盖 `DoAction` 与签名、序列化整条链路。
- **响应侧**:断言 `err == nil`、响应非 `nil`,并对业务字段做断言(如 `Code`、`Msg`、`Data` 及关键业务 ID、类型等**必须**通过 `fmt.Printf` 打印返回内容,便于人工核对逻辑是否正确。
- **风格**:与 `cs` 一致时优先使用 `t.Error` / `t.Errorf` + `return` 早退出;断言失败时除 `t.Errorf` 外可再 `fmt.Printf("%#+v\n", resp)`(及对 `*resp.Data`)便于排错。
#### 5.2 组织方式
- **同一能力的多条场景**(如白名单与黑名单):可拆成 `TestXxx`、`TestXxxBlack` 等若干函数,**每个函数内**仍应完整包含「请求校验 → 真实调用 → 响应断言 → 打印」,避免把断言拆成大量只测一行的小函数。
- **禁止**仅写「只校验 `InitParam`、不调 Client」的孤立用例作为唯一测试若需 mock无网/CI可另加辅助函数但不应替代上述真实调用用例作为唯一验收。
#### 5.3 输出与可读性
- 使用 `fmt.Printf("%#+v\n", resp)` 打印完整响应结构体;若 `Data` 为指针,再打印 `fmt.Printf("%#+v\n", *resp.Data)`
- 测试函数顶部用简短中文注释说明测的是哪条接口、什么场景。
#### 5.4 运行
```bash
go test ./services/<包名> -run Test<名称> -v
```