路由分组

当路由数量多了之后,全部写在一起会很乱。路由分组可以把相关的路由组织在一起,还能共享中间件和前缀。

基本分组

使用 Group() 创建路由组:

package main

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

func main() {
    r := gin.Default()

    api := r.Group("/api")
    {
        api.GET("/users", getUsers)
        api.GET("/posts", getPosts)
    }

    r.Run(":8080")
}

func getUsers(c *gin.Context) {
    c.JSON(200, gin.H{"users": []string{"Alice", "Bob"}})
}

func getPosts(c *gin.Context) {
    c.JSON(200, gin.H{"posts": []string{"Post 1", "Post 2"}})
}

访问 /api/users/api/posts 会分别调用对应的处理函数。

嵌套分组

分组可以嵌套:

r := gin.Default()

v1 := r.Group("/api/v1")
{
    users := v1.Group("/users")
    {
        users.GET("", listUsers)
        users.GET("/:id", getUser)
        users.POST("", createUser)
    }

    posts := v1.Group("/posts")
    {
        posts.GET("", listPosts)
        posts.GET("/:id", getPost)
    }
}

这样路由结构更清晰:

  • /api/v1/users
  • /api/v1/users/:id
  • /api/v1/posts
  • /api/v1/posts/:id

分组中间件

分组可以有自己的中间件,组内所有路由都会应用:

r := gin.Default()

api := r.Group("/api")
api.Use(func(c *gin.Context) {
    c.Set("api", true)
    c.Next()
})

api.GET("/data", func(c *gin.Context) {
    isAPI := c.GetBool("api")
    c.JSON(200, gin.H{"api": isAPI})
})

多个中间件

api := r.Group("/api")
api.Use(
    authMiddleware(),
    loggingMiddleware(),
    rateLimitMiddleware(),
)

实际应用示例

package main

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

func main() {
    r := gin.Default()

    setupRoutes(r)
    r.Run(":8080")
}

func setupRoutes(r *gin.Engine) {
    v1 := r.Group("/api/v1")
    v1.Use(apiVersionMiddleware())

    setupUserRoutes(v1)
    setupPostRoutes(v1)
}

func setupUserRoutes(rg *gin.RouterGroup) {
    users := rg.Group("/users")
    users.Use(userAuthMiddleware())

    users.GET("", listUsers)
    users.GET("/:id", getUser)
    users.POST("", createUser)
    users.PUT("/:id", updateUser)
    users.DELETE("/:id", deleteUser)
}

func setupPostRoutes(rg *gin.RouterGroup) {
    posts := rg.Group("/posts")
    posts.Use(postAuthMiddleware())

    posts.GET("", listPosts)
    posts.GET("/:id", getPost)
    posts.POST("", createPost)
    posts.PUT("/:id", updatePost)
    posts.DELETE("/:id", deletePost)
}

func apiVersionMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        c.Set("version", "v1")
        c.Next()
    }
}

func userAuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        token := c.GetHeader("Authorization")
        if token == "" {
            c.JSON(http.StatusUnauthorized, gin.H{"error": "需要认证"})
            c.Abort()
            return
        }
        c.Next()
    }
}

func postAuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        c.Next()
    }
}

func listUsers(c *gin.Context) {
    c.JSON(200, gin.H{"users": []string{}})
}

func getUser(c *gin.Context) {
    id := c.Param("id")
    c.JSON(200, gin.H{"id": id})
}

func createUser(c *gin.Context) {
    c.JSON(201, gin.H{"message": "用户创建成功"})
}

func updateUser(c *gin.Context) {
    id := c.Param("id")
    c.JSON(200, gin.H{"id": id, "message": "更新成功"})
}

func deleteUser(c *gin.Context) {
    id := c.Param("id")
    c.JSON(200, gin.H{"id": id, "message": "删除成功"})
}

func listPosts(c *gin.Context) {
    c.JSON(200, gin.H{"posts": []string{}})
}

func getPost(c *gin.Context) {
    id := c.Param("id")
    c.JSON(200, gin.H{"id": id})
}

func createPost(c *gin.Context) {
    c.JSON(201, gin.H{"message": "文章创建成功"})
}

func updatePost(c *gin.Context) {
    id := c.Param("id")
    c.JSON(200, gin.H{"id": id, "message": "更新成功"})
}

func deletePost(c *gin.Context) {
    id := c.Param("id")
    c.JSON(200, gin.H{"id": id, "message": "删除成功"})
}

分组的好处

路由分组带来的优势:

  • 代码组织:相关路由放在一起,容易维护
  • 共享中间件:组内路由自动应用组中间件
  • 路径前缀:避免重复写相同的前缀
  • 版本管理:方便管理 API 版本

小结

这一章学习了:

  • 创建路由分组
  • 嵌套分组
  • 分组中间件
  • 实际项目中的应用