Go 語言系列(七):專案結構與路由

這是 Go 語言從零到 Web 應用系列的第七篇。上一篇我們建立了第一個 API Server,但所有程式碼都在一個檔案裡。這篇要來學如何組織一個可維護的專案結構。 專案目錄結構 Go 社群雖然沒有強制的專案結構,但有一個被廣泛採用的慣例。以下是我們的 Web 應用將使用的結構: bookapi/ ├── cmd/ │ └── server/ │ └── main.go # 程式進入點 ├── internal/ │ ├── handler/ │ │ └── book.go # HTTP handler │ ├── middleware/ │ │ ├── logging.go # 日誌中間件 │ │ └── recovery.go # Panic recovery 中間件 │ ├── model/ │ │ └── book.go # 資料模型 │ └── store/ │ └── book.go # 資料存取層 ├── go.mod ├── go.sum └── .env # 環境變數(不進版控) 目錄說明 cmd/:可執行程式的進入點。每個子目錄對應一個執行檔 internal/:私有程式碼,Go 編譯器會阻止外部套件引用這個目錄下的程式碼 handler/:HTTP 請求處理器 middleware/:中間件 model/:資料模型定義 store/:資料存取邏輯 初始化專案 mkdir bookapi && cd bookapi go mod init bookapi 定義資料模型 internal/model/book.go package model import "time" type Book struct { ID int `json:"id"` Title string `json:"title"` Author string `json:"author"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } type CreateBookRequest struct { Title string `json:"title"` Author string `json:"author"` } func (r CreateBookRequest) Validate() map[string]string { errors := make(map[string]string) if r.Title == "" { errors["title"] = "title is required" } if r.Author == "" { errors["author"] = "author is required" } return errors } type UpdateBookRequest struct { Title *string `json:"title"` Author *string `json:"author"` } 使用獨立的 Request 型別而非直接用 Book,可以明確區分「客戶端送來的資料」和「系統內部的資料」。UpdateBookRequest 中的指標欄位讓我們能區分「沒有提供」和「設為空字串」。 ...

2026年2月24日 · 6 min · 1238 words · Jack