Tech Blog

Exploring Technology, Innovation & Future

繁體中文ProgrammingJuly 18, 2025

用Go建立RESTful API:從入門到實戰

Go語言因其優秀的性能和簡潔的語法,成為建立Web API的熱門選擇。本文將介紹如何使用Go從零開始建立一個完整的RESTful API,包括路由、中間件、資料庫操作和錯誤處理。

基礎HTTP伺服器

使用標準庫建立HTTP伺服器 Go的標準庫就提供了強大的HTTP支援:

```go package main

import ( "encoding/json" "fmt" "log" "net/http" )

type User struct { ID int `json:"id"` Name string `json:"name"` Email string `json:"email"` }

var users []User var nextID = 1

func main() { http.HandleFunc("/users", handleUsers) http.HandleFunc("/users/", handleUser) fmt.Println("伺服器運行於 :8080") log.Fatal(http.ListenAndServe(":8080", nil)) }

func handleUsers(w http.ResponseWriter, r *http.Request) { switch r.Method { case "GET": getUsers(w, r) case "POST": createUser(w, r) default: http.Error(w, "方法不被允許", http.StatusMethodNotAllowed) } } ```

使用Gin框架

安裝和基本設置 Gin是Go最流行的Web框架之一,提供了豐富的功能:

```bash go mod init api-example go get github.com/gin-gonic/gin ```

基本Gin應用: ```go package main

import ( "net/http" "strconv" "github.com/gin-gonic/gin" )

type User struct { ID int `json:"id"` Name string `json:"name"` Email string `json:"email"` }

var users = []User{ {ID: 1, Name: "張三", Email: "[email protected]"}, {ID: 2, Name: "李四", Email: "[email protected]"}, }

func main() { r := gin.Default() // 路由群組 api := r.Group("/api/v1") { api.GET("/users", getUsers) api.GET("/users/:id", getUserByID) api.POST("/users", createUser) api.PUT("/users/:id", updateUser) api.DELETE("/users/:id", deleteUser) } r.Run(":8080") } ```

API處理函數實現

獲取所有用戶: ```go func getUsers(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "data": users, "count": len(users), "message": "成功獲取用戶列表", }) } ```

根據ID獲取用戶: ```go func getUserByID(c *gin.Context) { idParam := c.Param("id") id, err := strconv.Atoi(idParam) if err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": "無效的用戶ID", }) return } for _, user := range users { if user.ID == id { c.JSON(http.StatusOK, gin.H{ "data": user, }) return } } c.JSON(http.StatusNotFound, gin.H{ "error": "用戶不存在", }) } ```

創建新用戶: ```go func createUser(c *gin.Context) { var newUser User if err := c.ShouldBindJSON(&newUser); err != nil { c.JSON(http.StatusBadRequest, gin.H{ "error": "無效的請求數據", "details": err.Error(), }) return } // 簡單驗證 if newUser.Name == "" || newUser.Email == "" { c.JSON(http.StatusBadRequest, gin.H{ "error": "姓名和郵箱不能為空", }) return } newUser.ID = len(users) + 1 users = append(users, newUser) c.JSON(http.StatusCreated, gin.H{ "data": newUser, "message": "用戶創建成功", }) } ```

中間件的使用

日誌中間件 ```go func Logger() gin.HandlerFunc { return gin.LoggerWithFormatter(func(param gin.LogFormatterParams) string { return fmt.Sprintf("%s - [%s] "%s %s %s %d %s "%s" %s" ", param.ClientIP, param.TimeStamp.Format(time.RFC1123), param.Method, param.Path, param.Request.Proto, param.StatusCode, param.Latency, param.Request.UserAgent(), param.ErrorMessage, ) }) } ```

CORS中間件 ```go func CORSMiddleware() gin.HandlerFunc { return func(c *gin.Context) { c.Writer.Header().Set("Access-Control-Allow-Origin", "*") c.Writer.Header().Set("Access-Control-Allow-Credentials", "true") c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With") c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT, DELETE") if c.Request.Method == "OPTIONS" { c.AbortWithStatus(204) return } c.Next() } } ```

認證中間件 ```go func AuthMiddleware() gin.HandlerFunc { return func(c *gin.Context) { token := c.GetHeader("Authorization") if token == "" { c.JSON(http.StatusUnauthorized, gin.H{ "error": "需要認證令牌", }) c.Abort() return } // 這裡可以驗證JWT令牌 if !isValidToken(token) { c.JSON(http.StatusUnauthorized, gin.H{ "error": "無效的認證令牌", }) c.Abort() return } c.Next() } }

func isValidToken(token string) bool { // 實際實作中這裡應該驗證JWT令牌 return token == "Bearer valid-token" } ```

資料庫整合

使用GORM ```go import ( "gorm.io/gorm" "gorm.io/driver/sqlite" )

type User struct { ID uint `json:"id" gorm:"primaryKey"` Name string `json:"name" gorm:"not null"` Email string `json:"email" gorm:"unique;not null"` }

func initDB() *gorm.DB { db, err := gorm.Open(sqlite.Open("users.db"), &gorm.Config{}) if err != nil { panic("連接資料庫失敗") } // 自動遷移 db.AutoMigrate(&User{}) return db }

func getUsersFromDB(c *gin.Context) { var users []User db := c.MustGet("db").(*gorm.DB) if err := db.Find(&users).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{ "error": "獲取用戶列表失敗", }) return } c.JSON(http.StatusOK, gin.H{ "data": users, }) } ```

錯誤處理

統一錯誤處理 ```go type APIError struct { Code int `json:"code"` Message string `json:"message"` Details string `json:"details,omitempty"` }

func ErrorHandler() gin.HandlerFunc { return func(c *gin.Context) { c.Next() if len(c.Errors) > 0 { err := c.Errors.Last() switch err.Type { case gin.ErrorTypeBind: c.JSON(http.StatusBadRequest, APIError{ Code: 400, Message: "請求參數錯誤", Details: err.Error(), }) default: c.JSON(http.StatusInternalServerError, APIError{ Code: 500, Message: "內部伺服器錯誤", }) } } } } ```

完整應用範例

```go func main() { r := gin.Default() // 載入中間件 r.Use(Logger()) r.Use(CORSMiddleware()) r.Use(ErrorHandler()) // 資料庫連接 db := initDB() r.Use(func(c *gin.Context) { c.Set("db", db) c.Next() }) // 路由設置 api := r.Group("/api/v1") { // 公開端點 api.POST("/login", login) api.POST("/register", register) // 需要認證的端點 protected := api.Group("/") protected.Use(AuthMiddleware()) { protected.GET("/users", getUsersFromDB) protected.GET("/users/:id", getUserByIDFromDB) protected.POST("/users", createUserInDB) protected.PUT("/users/:id", updateUserInDB) protected.DELETE("/users/:id", deleteUserFromDB) } } r.Run(":8080") } ```

測試API

使用curl測試 ```bash # 獲取所有用戶 curl -X GET http://localhost:8080/api/v1/users

# 創建新用戶 curl -X POST http://localhost:8080/api/v1/users \ -H "Content-Type: application/json" \ -d '{"name":"王五","email":"[email protected]"}'

# 更新用戶 curl -X PUT http://localhost:8080/api/v1/users/1 \ -H "Content-Type: application/json" \ -d '{"name":"王五更新","email":"[email protected]"}' ```

通過這個完整的範例,你可以建立一個功能完整的RESTful API。Go語言的標準庫和豐富的生態系統讓API開發變得既高效又愉快。記住要遵循RESTful設計原則,妥善處理錯誤,並確保API的安全性。

Related Articles