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
|
||
}
|
||
```
|