iT邦幫忙

2025 iThome 鐵人賽

DAY 6
0
Modern Web

Golang x Echo 30 天:零基礎GO , 後端入門系列 第 6

統一 API 回應與錯誤處理:從概念到一步一步打造

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20250920/20178818wT1JoCdc78.png

目標超單純:不管API成功或失敗,API 都回同一種外觀(JSON)。這樣前端不抓狂、後端好維護、除錯更快。就像統一制服,一眼認出同一隊。

為什麼要「統一格式」?

把 API 想成餐廳出餐:

  • 路由(Route):點餐櫃檯(例:/users/:id)
  • 處理器(Handler):服務生把單送進廚房
  • 回應(Response):端上桌的餐點(JSON)

如果成功回 JSON、失敗卻回文字或 HTML,就像今天用盤子、明天用紙袋——客人(前端)必定疑惑。解法:約定固定外觀,不管成功/失敗都長一樣。

成功:

{ 
  "status": "success", 
  "message": "OK", 
  "data": { "id": 1, "name": "小明" } 
} 

失敗:

{ 
  "status": "error", 
  "message": "查無此使用者", 
  "error_code": "USER_NOT_FOUND" 
} 

HTTP 狀態碼小抄(實務常用)

200 OK 成功|201 Created 新增成功|400 參數錯|401 未登入|403 沒權限|404 找不到|409 資料衝突|422 驗證沒過|500 伺服器錯誤

一步一步把 main.go 組起來(像堆樂高)

跟著貼,每一步都可編譯。最後會長成完整可跑的伺服器。

  1. 開場(可選,但建議)
mkdir echo-unified-api && cd echo-unified-api 
go mod init example.com/echo-unified-api 
go get github.com/labstack/echo/v4 
  1. 最小可執行:Hello Echo
package main 
 
import ( 
	"net/http" 
	"github.com/labstack/echo/v4" 
) 
 
func main() { 
	e := echo.New() 
	e.GET("/health", func(c echo.Context) error { 
		return c.String(http.StatusOK, "OK") 
	}) 
	e.Logger.Fatal(e.Start(":1323")) 
} 
  1. 定義「統一回應」的外觀
type ApiResponse struct { 
	Status    string      `json:"status"` 
	Message   string      `json:"message"` 
	Data      interface{} `json:"data,omitempty"` 
	ErrorCode string      `json:"error_code,omitempty"` 
} 
  1. 小工具:成功/失敗回傳
func JSONSuccess(c echo.Context, msg string, data interface{}, code int) error { 
	if code == 0 { code = http.StatusOK } 
	return c.JSON(code, ApiResponse{ Status: "success", Message: msg, Data: data }) 
} 
 
func JSONError(c echo.Context, msg, errCode string, httpCode int) error { 
	if httpCode == 0 { httpCode = http.StatusBadRequest } 
	return c.JSON(httpCode, ApiResponse{ Status: "error", Message: msg, ErrorCode: errCode }) 
} 
  1. 健康檢查 API
func Health(c echo.Context) error { 
	return JSONSuccess(c, "OK", map[string]any{"service": "up"}, http.StatusOK) 
} 
  1. 模擬資料
type User struct { 
	ID    int    `json:"id"` 
	Name  string `json:"name"` 
	Email string `json:"email"` 
} 
 
var fakeUsers = map[int]User{ 
	1: {ID: 1, Name: "小明", Email: "ming@example.com"}, 
	2: {ID: 2, Name: "小美", Email: "mei@example.com"}, 
} 
  1. 依 ID 取使用者
func GetUserByID(c echo.Context) error { 
	idStr := c.Param("id") 
	id, err := strconv.Atoi(idStr) 
	if err != nil || id <= 0 { 
		return JSONError(c, "參數格式錯誤:id 應為正整數", "BAD_ID_FORMAT", http.StatusBadRequest) 
	} 
	u, ok := fakeUsers[id] 
	if !ok { 
		return JSONError(c, "查無此使用者", "USER_NOT_FOUND", http.StatusNotFound) 
	} 
	return JSONSuccess(c, "使用者資料取得成功", u, http.StatusOK) 
} 

路由掛法:

api := e.Group("/api") 
api.GET("/health", Health) 
api.GET("/users/:id", GetUserByID) 
  1. 基本中介層
e.Use(middleware.Logger())  // 請求日誌 
e.Use(middleware.Recover()) // panic 自動復原 
e.Use(middleware.CORS())    // 跨域 
  1. 客製 HTTPErrorHandler
func makeHTTPErrorHandler() echo.HTTPErrorHandler { 
	return func(err error, c echo.Context) { 
		code := http.StatusInternalServerError 
		msg := "伺服器內部錯誤" 
		errCode := "INTERNAL_SERVER_ERROR" 
 
		if he, ok := err.(*echo.HTTPError); ok { 
			code = he.Code 
			if s, ok := he.Message.(string); ok && s != "" { msg = s } else if he.Message != nil { 
				msg = fmt.Sprintf("%v", he.Message) 
			} 
			switch code { 
			case http.StatusNotFound: errCode = "ROUTE_NOT_FOUND" 
			case http.StatusBadRequest: errCode = "BAD_REQUEST" 
			case http.StatusUnauthorized: errCode = "UNAUTHORIZED" 
			case http.StatusForbidden: errCode = "FORBIDDEN" 
			} 
		} 
 
		if !c.Response().Committed { 
			_ = c.JSON(code, ApiResponse{ Status: "error", Message: msg, ErrorCode: errCode }) 
		} 
	} 
} 

在 main() 啟用:

e.HTTPErrorHandler = makeHTTPErrorHandler() 

完整版 main.go

...完整程式碼如前所示... 

測試一下

go run main.go 
 
# 成功 
curl -i http://localhost:1323/api/users/1 
 
# 失敗:查無 
curl -i http://localhost:1323/api/users/9999 
 
# 健康檢查 
curl -i http://localhost:1323/api/health 
 
# 路由不存在 
curl -i http://localhost:1323/api/unknown 

出場前檢查

• 回應都有 status、message
• 成功用 data,失敗用 error_code
• HTTP 狀態碼用對
• 已設定 HTTPErrorHandler
• 常用 JSONSuccess / JSONError

https://ithelp.ithome.com.tw/upload/images/20250920/201788185pL2QPHbn4.png


上一篇
Echo Middleware 實戰:中介層就像速食店的SOP
下一篇
Go 應用程式設定管理:12-Factor 原則的簡單版
系列文
Golang x Echo 30 天:零基礎GO , 後端入門8
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言