135 lines
3.5 KiB
Markdown
135 lines
3.5 KiB
Markdown
|
|
# CLAUDE.md
|
|||
|
|
|
|||
|
|
本文件为 Claude Code (claude.ai/code) 在此仓库中工作时提供指引。
|
|||
|
|
|
|||
|
|
## 常用命令
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 运行某个 service 的全部测试
|
|||
|
|
go test ./services/apk/...
|
|||
|
|
|
|||
|
|
# 运行单个测试函数
|
|||
|
|
go test ./services/apk/... -run TestClient_GetUserInfo -v
|
|||
|
|
|
|||
|
|
# 编译检查
|
|||
|
|
go build ./...
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 整体架构
|
|||
|
|
|
|||
|
|
分两层:
|
|||
|
|
|
|||
|
|
- `sdk/`:核心框架,处理签名、HTTP 请求、响应解析,不含业务逻辑
|
|||
|
|
- `services/<name>/`:各业务服务封装,每个包是一个独立 SDK client
|
|||
|
|
|
|||
|
|
### sdk/ 核心流程
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
调用方 → Client.DoAction(req, resp)
|
|||
|
|
→ auth.Sign(req, signer) # 根据 credential 类型签名
|
|||
|
|
→ req.BuildUrl() # RpcRequest 拼接域名+路径+query
|
|||
|
|
→ HTTP 请求
|
|||
|
|
→ responses.Unmarshal(resp) # JSON 反序列化
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
- `sdk/auth/credentials/`:三种凭证类型(AccessKey、StsToken、AliAppcode)
|
|||
|
|
- `sdk/auth/signers/`:对应签名器实现
|
|||
|
|
- `sdk/requests/`:`RpcRequest`(主流)和 `RoaRequest` 两种请求风格;字段通过 struct tag `position:"Body|Query|Header"` 和 `field:"xxx"` 声明参数位置
|
|||
|
|
- `sdk/config.go`:`Config` 结构体,字段用 `default:"..."` tag 自动初始化
|
|||
|
|
|
|||
|
|
### services/ 统一模式
|
|||
|
|
|
|||
|
|
每个服务包含:
|
|||
|
|
|
|||
|
|
| 文件 | 职责 |
|
|||
|
|
|------|------|
|
|||
|
|
| `client.go` | 定义 `Client`(内嵌 `sdk.Client`)、`HOST`、`VERSION` 常量,以及所有对外方法 |
|
|||
|
|
| `xxx_action.go` | 每个接口一个文件,包含 Request/Response 结构体和两个工厂函数 |
|
|||
|
|
|
|||
|
|
## 添加新接口的标准步骤
|
|||
|
|
|
|||
|
|
**1. 新建 `services/<name>/new_action.go`:**
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
package <name>
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests"
|
|||
|
|
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/responses"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
type NewActionRequest struct {
|
|||
|
|
*requests.RpcRequest
|
|||
|
|
Field1 string `position:"Body" field:"field1" default:""`
|
|||
|
|
Field2 int64 `position:"Body" field:"field2"`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
type NewActionResponse struct {
|
|||
|
|
*responses.BaseResponse
|
|||
|
|
Code int `json:"code"`
|
|||
|
|
Msg string `json:"msg"`
|
|||
|
|
Data struct {
|
|||
|
|
// ...
|
|||
|
|
} `json:"data"`
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func CreateNewActionRequest() *NewActionRequest {
|
|||
|
|
req := &NewActionRequest{RpcRequest: &requests.RpcRequest{}}
|
|||
|
|
req.InitWithApiInfo(HOST, VERSION, "/api/path/here")
|
|||
|
|
req.Method = requests.POST
|
|||
|
|
return req
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func CreateNewActionResponse() *NewActionResponse {
|
|||
|
|
return &NewActionResponse{BaseResponse: &responses.BaseResponse{}}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**2. 在 `client.go` 添加方法:**
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
func (c *Client) NewAction(req *NewActionRequest) (response *NewActionResponse, err error) {
|
|||
|
|
response = CreateNewActionResponse()
|
|||
|
|
err = c.DoAction(req, response)
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## HOST 两种写法
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// 简单写法(内部服务,hostname 由调用方注入)
|
|||
|
|
var HOST = requests.Host{Default: "service-name"}
|
|||
|
|
|
|||
|
|
// 带环境路由写法(外部服务,各环境域名不同)
|
|||
|
|
var HOST = requests.Host{
|
|||
|
|
Default: "api.example.com",
|
|||
|
|
Func: func(env string) string {
|
|||
|
|
return map[string]string{
|
|||
|
|
requests.RELEASE: "api.example.com",
|
|||
|
|
requests.TEST: "test.api.example.com",
|
|||
|
|
}[env]
|
|||
|
|
},
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
环境常量:`requests.RELEASE`、`requests.PRE`、`requests.TEST`
|
|||
|
|
|
|||
|
|
## Client 初始化两种模式
|
|||
|
|
|
|||
|
|
```go
|
|||
|
|
// 模式一:无需认证(apk、callback 等内部服务)
|
|||
|
|
func NewClient() *Client {
|
|||
|
|
client := &Client{}
|
|||
|
|
client.InitWithAccessKey("", "", "")
|
|||
|
|
return client
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 模式二:需要认证(sso、pay 等)
|
|||
|
|
func NewClient() (*Client, error) {
|
|||
|
|
client := new(Client)
|
|||
|
|
err := client.Init()
|
|||
|
|
return client, err
|
|||
|
|
}
|
|||
|
|
```
|