# HTTP 統一回應

## 分工

| 層 | 職責 |
|----|------|
| **Logic** | `return data, err`（`err` 為 `*errs.Error` 或標準 `error`） |
| **Handler** | `response.Write(ctx, w, data, err)` |
| **`.api`** | 只描述 `data` 的型別（如 `PingData`），不描述外層 `Status` |

## Handler 範例

有 request 的 API，模板會自動生成 **參數綁定 + 驗證**（`httpx.Parse` → `svcCtx.Validator.ValidateAll`）：

```go
var req types.GetUserReq
if err := httpx.Parse(r, &req); err != nil {
    response.Write(r.Context(), w, nil, response.WrapRequestError(err)) // → 400 InputInvalidFormat
    return
}
if err := svcCtx.Validator.ValidateAll(&req); err != nil {
    response.Write(r.Context(), w, nil, response.WrapRequestError(err)) // validate:"..." 失敗
    return
}
data, err := l.GetUser(&req)
response.Write(r.Context(), w, data, err)
```

在 `.api` 的 request 欄位加 `validate:"required,email"` 等 tag，`make gen-api` 後會寫入 `internal/types`，無需在 Logic 再手動驗證。

無 request 的 API（如 `GET /health`）不會生成 Parse / ValidateAll 區塊，屬正常行為。

在 `main` 可設定驗證錯誤使用的 scope：

```go
response.RequestErrScope = code.Facade
```

`.api` 的 request struct 可加 `validate:` tag 或實作 `Validate() error`，由 go-zero `httpx.Parse` 觸發。

進階驗證可使用 `svcCtx.Validator.ValidateAll(&req)`（`gateway/internal/library/validate`）。回傳的 `validate.ValidationErrors` 經 `response.WrapRequestError` 會映射為 **400** `InputInvalidFormat`。

## Logic 範例

各模組 logic / usecase 綁定對應 scope（**不要**一律用 `code.Facade`）：

```go
// internal/logic/member/errors.go
var errb = errs.For(code.Member)

func (l *XLogic) GetUser(req *types.GetUserReq) (*types.UserVO, error) {
    out, err := l.svcCtx.MemberProfile.Get(...)
    if err != nil {
        return nil, err // Member scope 錯誤原樣傳遞
    }
    return vo, nil
}
```

## 回應 JSON

成功（HTTP 200）：

```json
{ "code": 102000, "message": "SUCCESS", "data": { ... } }
```

失敗（HTTP 依 category，如 404；Member scope 範例）：

```json
{
  "code": 29301000,
  "message": "member not found",
  "error": { "biz_code": "29301000", "scope": 29, "category": 301, "detail": 0 }
}
```

## goctl 模板（可選）

專案模板路徑：`generate/goctl/api/handler.tpl`（**不是** `api/gogen/`）。

`make gen-api` 已帶 `-home generate/goctl`，**新建的 handler** 會自動使用 `response.Write`。

注意：已存在的 handler 檔案 goctl **不會覆寫**（會顯示 `exists, ignored`）。新增 API 沒問題；若要重生成舊 handler，需先刪除該檔再 `make gen-api`。
