iT邦幫忙

2024 iThome 鐵人賽

DAY 18
0
Modern Web

Go 快 Go 高效: 從基礎語法到現代Web應用開發系列 第 18

【Day18】輕量 Web 框架 | 透過 Gin + router 來建構 RESTful API

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20240926/20161850cA2znBNdoF.jpg
(📎Github 倉庫) | (📎官方文檔)

Gin 是一個非常輕量且高效能的網頁框架,適合用來構建 RESTful APIsWeb 應用程式。它因為簡單易用、效能優異以及強大的路由功能,成為許多 Golang 開發者的首選。

那我會選擇他來介紹是因爲 Gin 在處理大量的 HTTP 請求時能夠保持較高的效能,即使在高流量場景下也能有非常快速的響應。


  • 安裝套件

一樣在 terminal 下方輸入這段指令

go get -u github.com/gin-gonic/gin

確保在 go.mod 有下面內容

module demo

go 1.23.0

require github.com/gin-gonic/gin v1.10.0

require (
	github.com/bytedance/sonic v1.12.3 // indirect
	github.com/bytedance/sonic/loader v0.2.0 // indirect
	github.com/cloudwego/base64x v0.1.4 // indirect
	github.com/cloudwego/iasm v0.2.0 // indirect
	github.com/gabriel-vasile/mimetype v1.4.5 // indirect
	github.com/gin-contrib/sse v0.1.0 // indirect
	github.com/go-playground/locales v0.14.1 // indirect
	github.com/go-playground/universal-translator v0.18.1 // indirect
	github.com/go-playground/validator/v10 v10.22.1 // indirect
	github.com/goccy/go-json v0.10.3 // indirect
	github.com/json-iterator/go v1.1.12 // indirect
	github.com/klauspost/cpuid/v2 v2.2.8 // indirect
	github.com/leodido/go-urn v1.4.0 // indirect
	github.com/mattn/go-isatty v0.0.20 // indirect
	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
	github.com/modern-go/reflect2 v1.0.2 // indirect
	github.com/pelletier/go-toml/v2 v2.2.3 // indirect
	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
	github.com/ugorji/go/codec v1.2.12 // indirect
	golang.org/x/arch v0.10.0 // indirect
	golang.org/x/crypto v0.27.0 // indirect
	golang.org/x/net v0.29.0 // indirect
	golang.org/x/sys v0.25.0 // indirect
	golang.org/x/text v0.18.0 // indirect
	google.golang.org/protobuf v1.34.2 // indirect
	gopkg.in/yaml.v3 v3.0.1 // indirect
)

那這是我會介紹到的檔案結構,除了 handlerepository 的具體實現會留到之後介紹外,剩下的會帶大家做個小複習!

demo/
├── main.go 
├── handler/
│   ├── userHandler.go
├── repositories/
│   ├── userRepo.go
├── database/
│   └── db.go
├── ├── models/
│       └── userModel.go
└── routes/
    └── routes.go

首先是我們的 /demo/database 底下的內容。

  • userModel.go
type User struct {
	ID   uint   `gorm:"primaryKey"`
	Name string `gorm:"size:255"`
	Age  int
}
  • db.go
package database

import (
	"demo/database/models"
	"fmt"
	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

type Database struct {
	Context *gorm.DB
}

var DB *Database

func ConnectDB() {

	dsn := "host=localhost user=imac dbname=mydb port=5432 sslmode=disable timezone=Asia/Taipei"

	var db *gorm.DB
	var err error

	db, err = gorm.Open(postgres.Open(dsn), &gorm.Config{})

	if err != nil {
		panic("failed to connect database")
	} else {
		fmt.Println("connected success")
	}

	if err := db.AutoMigrate(&models.User{}); err != nil {
		panic("failed to auto migrate")
	} else {
		migrator := db.Migrator()
		migrator.HasTable(&models.User{})
	}

	DB = &Database{
		Context: db,
	}
}

跟之前的連接資料庫不同的地方在於,我們對此做了一些小調整

  • Database 結構體:封裝了資料庫連線,讓操作資料庫更加結構化。
  • ConnectDB 函數:負責建立資料庫連線、處理錯誤、自動進行資料表遷移,並且將連線存儲在全域變數 DB 中。

最後我們將建立好的資料庫連線(db)包裝進 Database 結構體,並賦值給全域變數 DB,這樣應用的其他地方就可以通過 DB.Context 來存取資料庫,進行查詢、插入、更新等操作,而不必擔心重複建立資料庫連線。


再來是我們的 /demo/handler

  • userHandler.go
package handler

import (
	"github.com/gin-gonic/gin"
)

/*
- 查詢 (Query)
  - Get
  - GetAll
- 修改 (Modify)
  - Create
  - Update
  - Delete
*/

func GetHandle(context *gin.Context) {

}

func GetAllHandle(context *gin.Context) {

}

func CreateHandle(context *gin.Context) {

}

func UpdateHandle(context *gin.Context) {

}

func DeleteHandle(context *gin.Context) {

}

下篇會再做更詳細的介紹。


接著我們來實現路由的部分 demo/routes

在 API 開發中,路由(Router)是負責將 HTTP 請求(如 GET、POST、PUT、DELETE 等)導向對應處理函數的核心組件。簡單來說,當一個請求到達伺服器時,路由會根據請求的 URL 路徑和 HTTP 方法,決定應該由哪個處理函數來處理這個請求。

  • routes.go
package routes

import (
	api "demo/handler"
	"github.com/gin-gonic/gin"
	"log"
)

type rawValue string

const (
	// User Profile
	UserProfile rawValue = "/user/:id"
	User        rawValue = "/user"
	UserList    rawValue = "/users"
)

func InitRouter() {
	app := gin.Default()

	// 設定代理伺服器的 IP 或網域
	trustedProxies := []string{"127.0.0.1"} // 設定本地開發環境
	if err := app.SetTrustedProxies(trustedProxies); err != nil {
		log.Fatalf("設定信任的代理伺服器失敗: %v", err)
	}

	userApi := app.Group("/api/v1")
	{
		// User Identity
		userApi.GET(string(UserProfile), api.GetHandle)
		userApi.GET(string(UserList), api.GetAllHandle)
		userApi.POST(string(User), api.CreateHandle)
		userApi.PUT(string(User), api.UpdateHandle)
		userApi.DELETE(string(User), api.DeleteHandle)

	}

	err := app.Run(":8080")
	if err != nil {
		panic(err)
	}
}
  • 首先我們使用 const 定義路由路徑的常數。
  • 接著我們看到 InitRouter 方法
    • gin.Default():返回一個包含預設中介軟體的路由器實例。
    • SetTrustedProxies:設定應用程式信任的代理伺服器,確保應用程式只信任來自特定來源的代理。因為我們只是在開發環境中,所以通常設為 127.0.0.1(本地回環地址)。
    • app.Group("/api/v1"):創建一個路由群組,所有在此群組下定義的路由都會有共同的前綴 /api/v1。這有助於版本管理和路由組織。
    • app.Run(":8080"):啟動 HTTP 伺服器,監聽本機的 8080 埠。若啟動失敗,將觸發 panic,終止應用程式。

  • 最後回到我們的 main.go
package main

import (
	"demo/database"
	"demo/routes"
)
func main() {
	database.ConnectDB()
	routes.InitRouter()
}

接著我們試著執行程式看看,會出現什麼吧!

[GIN-debug] GET    /api/v1/users    --> demo/handler.GetAllHandle (3 handlers)
[GIN-debug] POST   /api/v1/user     --> demo/handler.CreateHandle (3 handlers)
[GIN-debug] PUT    /api/v1/user     --> demo/handler.UpdateHandle (3 handlers)
[GIN-debug] DELETE /api/v1/user     --> demo/handler.DeleteHandle (3 handlers)
[GIN-debug] Listening and serving HTTP on :8080

那可以看到他已經在我們本地的8080埠號啟動了,那今天就先到這邊,明天我們再來接續下面的內容!


總結

在本篇介紹中,我們搭建了一個基於 Gin 框架的基本 Go 專案結構,涵蓋了資料庫連接、模型定義、路由設置及處理函數的基礎實作。通過使用 GORM 進行資料庫操作,我們確保了資料庫連線的結構化管理和自動遷移功能。同時,通過路由群組的方式,有效地組織了 API 路由,並設置了信任的代理伺服器以增強應用的安全性。最後,我們成功啟動了伺服器,並確認了各個路由的正確配置。接下來,將進一步實作具體的處理函數,完成完整的 CRUD 操作。


延伸閱讀

如果需要嘗試其他解決方案可以參考下面這些框架來開發


上一篇
【Day17】連接資料庫 II | 使用 GORM 來與 PostgreSQL 互動
下一篇
【Day19】RESTful API 設計 I | 讀取方式 (Get) 介紹
系列文
Go 快 Go 高效: 從基礎語法到現代Web應用開發20
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
c8763yee
iT邦新手 4 級 ‧ 2024-09-26 19:27:07

這幾個架構跟iris比起來有啥優劣?

我要留言

立即登入留言