# 新增 HTTP 接口流程

项目 `controller` 定义于 `backend/app/http/[module_name]/[controller].go` 文件中。 每个 `controller` 负责处理一组相关的 HTTP 请求。 例如，`backend/app/http/super/tenant.go` 负责处理与租户相关的请求。

## 新增接口步骤

1. 在 `controller` 中新增方法以处理特定的 HTTP 请求。 例如，在 `tenant.go` 新增一个 `list` 方法来处理列出租户的请求。
2. 定义相关 `swagger` 注解以生成 API 文档。 这些注解通常位于方法上方，描述了请求路径、参数和响应格式。
3. 在模块 `dto/`（数据传输对象）目录中定义请求和响应的数据结构, 以确保数据的一致性和类型安全。
4. 运行 `atomctl gen route` 生成路由文件，确保新接口被正确注册。
5. 运行 `atomctl gen provider` 生成路由文件，确保新接口被正确注册。

## 接口定义示例：

1. 实现需要返回数据的接口。

```go
func (*tenant) list(ctx fiber.Ctx, filter *dto.TenantFilter) (*requests.Pager, error) {
	return nil,nil
}
```

2. 实现不需要返回数据的接口

```go
func (*tenant) update(ctx fiber.Ctx, tenantID int64, form *dto.TenantExpireUpdateForm) error {
	return nil
}
```

## swagger 注解说明

-   **@Summary**: 接口的简要描述。
-   **@Description**: 接口的详细描述。
-   **@Tags**: 接口所属的分类标签。
-   **@Accept**: 接口接受的数据格式。通常为 `json`
-   **@Produce**: 接口返回的数据格式。通常为 `json`
-   **@Param**: 定义接口的参数，包括参数名称、数据来源位置、数据类型、是否必须、和描述。如：`//	@Param form	body dto.LoginForm true	"form"`
-   **@Success**: 定义接口成功时的响应格式。如：
    -   返回分页列表 `// @Success 200 {object} requests.Pager{items=dto.Item}`
    -   直接返回对象 `// @Success 200 {object} dto.Item`
    -   返回数据对象列表 `// @Success 200 {array} dto.Item`
-   **@Router**: 定义接口的路由信息，包括路径和请求方法。如：`// @Router /super/tenants [get|post|put|delete|patch]`, 如果需要定义 path 参数，使用 `:paramName` 语法表示，如：`/super/tenants/:tenantID`
-   **@Bind**: 定义参数绑定方式，格式： `@Bind <paramName> <position> [key(<key>)] [model(<field>|<model>[:<field>])]`
    -   `paramName` 与方法参数名一致（大小写敏感）
    -   `position`：`path`、`query`、`body`、`header`、`cookie`、`local`、`file`
    -   可选：
        -   `key()` 覆盖默认键名；
        -   `model()` 详见“模型绑定”。

### 参数绑定

-   query：标量用 `QueryParam[T]("key")`，非标量用 `Query[T]("key")`
-   path：标量用 `PathParam[T]("key")`，非标量用 `Path[T]("key")`
    -   若使用 `model()`（仅在 path 有效），会按字段值查询并绑定为 `T`，详见下文
-   header：`Header[T]("key")`
-   body：`Body[T]("key")`
-   cookie：`string` 用 `CookieParam("key")`，其他用 `Cookie[T]("key")`
-   file：`File[multipart.FileHeader]("key")`
-   local：`Local[T]("key")`

说明：

-   标量类型集合：`string`、`int`、`int32`、`int64`、`float32`、`float64`、`bool`
-   `key` 默认等于 `paramName`；设置 `key(...)` 后以其为准
-   `file` 使用固定类型 `multipart.FileHeader`

### 类型与指针处理

-   支持 `T`、`*T`、`pkg.T`、`*pkg.T`；会正确收集选择子表达式对应 import
-   忽略结尾为 `Context` 或 `Ctx` 的参数（框架上下文）
-   指针处理：除 `local` 外会去掉前导 `*` 作为泛型实参；`local` 保留指针（便于写回）

### 模型绑定

当 `@Bind ... model(...)` 配合 `position=path` 使用时，将根据路径参数值查询模型并绑定为方法参数类型的实例（`T` 来自方法参数）。

-   语法：
    -   仅字段：`model(id)`（推荐）
    -   指定字段与类型：`model(id:int)`、`model(code:string)`（用于非字符串路径参数）
    -   指定类型与字段：`model(pkg.Type:field)` 或 `model(pkg.Type)`（字段缺省为 `id`）
-   行为：
    -   生成的绑定器会按给定字段构造查询条件并返回首条记录
    -   自动注入 import：`field "go.ipao.vip/gen/field"`，用于构造字段条件表达式

示例：

```go
// @Router /users/:id [get]
// @Bind user path key(id) model(id)
func (uc *UserController) Show(ctx context.Context, user *models.User) (*UserDTO, error)
```
