# 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`。