寫過幾個正式 Go API 後,我的專案結構與中介層心得
Programming·2025年7月18日·4 分鐘閱讀

寫過幾個正式 Go API 後,我的專案結構與中介層心得

用 Go 寫一個 API 很快,net/http 幾行就能跑。但「能跑」和「能讓三個人一起維護兩年」是兩回事。這篇是我交付過幾個正式 Go 後端服務之後,沉澱下來的專案結構與中介層做法,沒有標準答案,但都是踩過坑換來的。

別一開始就上重架構

寫過幾個正式 Go API 後,我的專案結構與中介層心得:本文架構

Go 社群很愛討論 Clean Architecture、DDD、各種分層。我的態度是:分層是手段不是目的。一個還在找產品方向的服務,硬套五層架構,只會讓改一個欄位要動五個檔案。

我多數專案就務實的三層:

  • handler 層:只負責解析請求、驗證輸入、組裝回應,不寫業務邏輯
  • service 層:業務邏輯集中在這,可以獨立測試、不依賴 HTTP
  • repository 層:把資料庫操作隔離起來,service 不直接碰 SQL

這三層的核心價值是:業務邏輯不該知道自己是被 HTTP 呼叫的。哪天要加一個 gRPC 入口或 CLI,service 完全不用改。

用 interface 切開依賴

service 依賴 repository 時,我讓 service 定義它需要的那個小介面,repository 去實作。這樣 service 的測試完全不需要真的資料庫,給一個假的實作就好。前面那篇講 Go 心得時提到「介面由使用方定義」,在這裡就是最實際的應用。

中介層(middleware)放橫切關注點

凡是「每個請求都要做」的事,我都收斂成 middleware,而不是散在每個 handler 裡。我固定會有的幾個:

  • Recover:攔截 panic,回 500,避免一個請求把整個服務打掛
  • Logging:記錄每個請求的方法、路徑、狀態碼、耗時,附上一個 request id
  • Request ID:每個請求發一個唯一 id,貫穿 log 與下游呼叫,出事時能把一條請求的軌跡串起來
  • 認證:驗 token、把使用者資訊放進 context 往下傳
  • 限流/逾時:保護下游不被打爆

middleware 的順序很重要。Recover 要在最外層,才接得到內層所有的 panic;Logging 通常也要夠外層,才能記到完整的耗時。

錯誤處理要對外乾淨、對內詳細

我會把「給使用者看的錯誤」和「給工程師看的錯誤」分開。對外回傳穩定的錯誤碼與簡短訊息,不要把資料庫錯誤、堆疊細節吐給使用者(那是資安問題);對內則用包裝把上下文一層層加上去,log 裡才查得到根因。

handler 我盡量收斂到一個統一的地方把 error 轉成 HTTP 回應,而不是每個 handler 自己 if 一大串。

context 一路傳下去

從 handler 進來的 context,我會一路傳到 service、repository,DB 查詢也吃這個 context。好處是請求一旦取消或逾時,整條鏈路都能即時收手,不會有人還在傻傻地跑一個沒人要的查詢。

設定與祕密不要寫死

連線字串、金鑰這些用環境變數或設定檔注入,絕不寫死在程式裡。啟動時就把設定讀好、驗證好(缺了必要設定就讓它直接啟動失敗),比執行到一半才爆掉好得多。

小結

我交付正式 Go API 的幾個原則:

  • 先簡單三層,別為架構而架構
  • 業務邏輯不依賴 HTTP,用 interface 切依賴
  • 橫切關注點(recover、log、request id、認證、限流)放 middleware,注意順序
  • 錯誤對外乾淨、對內詳細,統一轉換
  • context 一路傳,設定從外部注入並在啟動時驗證

這些東西不華麗,但它們是讓一個服務上線後「半夜不會把你吵醒、出事查得到」的基礎。

留言討論

有想法、有不同經驗、或想糾正我?歡迎在下面留言,免註冊,填個暱稱就能留。

相關文章