路由的设计可谓仁者见仁智者见智,没有对错好坏,只有适合与否。
如果你设计得好,后面使用的人比较顺手,如果设计不好估计会被骂爹,就这么简单。
我们先来看一组API:
GET /message/{msg_id} 获取留言明细
GET /message/{user_name} 获取用户发布的留言列表
GET /message/top 获取最热留言列表
你给这组 API 打多少分?
可以先记下,待看完这篇文文章再回顾下,和你此刻的想法有什么区别?
Gin 使用的是 httprouter 作为路由库,Github 地址如下:
https://github.com/julienschmidt/httprouter
httprouter 的性能好,但是功能并是特别强大,比如:路由不支持正则。
在功能强大和性能强这两方面,自古是鱼和熊掌不可兼得。
Gin 选择了性能,牺牲掉了功能。
但是这个路由库的功能,对于大部分项目完全够用。
假如我们需要获取一条留言的详情,就需要在我们 URL 里面取到具体的留言 ID 才行。
此时我们就有获取 URL 里面的值需求,Gin 是支持的,代码如下:
r := gin.Default()
r.GET("/message/:msg_id", func(c *gin.Context) {
c.String(http.StatusOK, "留言ID为:%s", c.Param("msg_id"))
})
r.Run(":8080")
效果如下:
现在再回到最初的那组路由,我们现在去加入 最热留言列表 在后面,代码如下:
r := gin.Default()
r.GET("/message/:msg_id", func(c *gin.Context) {
c.String(http.StatusOK, "留言ID为:%s", c.Param("msg_id"))
})
r.GET("/message/top", func(c *gin.Context) {
c.String(http.StatusOK, "获取最新留言")
})
r.Run(":8080")
在新版 Gin 里面,这样写虽然不会报错,但是并不建议这样去设计路由,因为他容易与上面的详情接口产生混淆。
以下只是建议,但是实际开发中,一般得根据实际需要进行调整。
我相信你在调用一些开源接口时,会发现,他们的接口一般是以 v1 这种字样开头的。
比如:/v1/xxxx
为什么要这样设计呢?
我们在设计开发完 API 之后不可能以后都不迭代了吧。
当我们发现我们设计的接口需要修改时,却发现这个接口已经上线,被无数人使用。
这时候如果你没有版本控制,你就很难做到向下兼容。
比如:
/v1/topics
/v1/users
/v1/getUsers (不推荐)
这在 restfull 风格的设计里,这样是最常见的。
建议每种url代表了一种资源。
比如:
/v1/users (取全部)
/v1/users?limit=10 (取10条)
结合我们的接口设计规则,我们做一下调整。
关闭版本管理,Gin 里面我们可以使用路由分组,所以我们可以创建一个组来管理相关版本的 API,如:
r := gin.Default()
// 新建一个路由组
v1 := r.Group("/v1")
// 留言列表接口
v1.GET("", func(c *gin.Context) {
userId := c.Query("user_id")
if userId == ""{
c.String(http.StatusOK, "获取全部留言列表")
}else{
c.String(http.StatusOK, "获取用户名为 %s 的留言列表", userId)
}
})
// 留言详情接口
v1.GET("/message/:msg_id", func(c *gin.Context) {
c.String(http.StatusOK, "获取 msg_id=%s 的留言详情", c.Param("msg_id"))
})
r.Run(":8080")
到这里我们的 Gin 路由设计分享就结束了。
下一篇文章,我们对代码进行封装以及使用中间件”鉴权“。