一些路由管理混亂的例子

首先,我先給大家看一個(gè)曾經(jīng)維護(hù)過(guò)的項(xiàng)目的路由文件 router.go, 這個(gè)項(xiàng)目用的也是Gin框架,整個(gè)文件里500多行全是API接口的路由。

你說(shuō)這么寫(xiě)不好維護(hù)吧,全項(xiàng)目的路由都在這里不用其他地方找,按能用就行的標(biāo)準(zhǔn),確實(shí)是能用。

而且Gin的官方文檔里在路由這塊的例子確實(shí)也是這么寫(xiě)的。

// Gin 官方文檔示例
func main() {
router := gin.Default()

// 簡(jiǎn)單的路由組: v1
v1 := router.Group("/v1")
{
v1.POST("/login", loginEndpoint)
v1.POST("/submit", submitEndpoint)
v1.POST("/read", readEndpoint)
}

// 簡(jiǎn)單的路由組: v2
v2 := router.Group("/v2")
{
v2.POST("/login", loginEndpoint)
v2.POST("/submit", submitEndpoint)
v2.POST("/read", readEndpoint)
}

router.Run(":8080")
}

隨著項(xiàng)目開(kāi)發(fā)的迭代,我們寫(xiě)的接口往往會(huì)越來(lái)越多,如果還按上面這樣把API的路由寫(xiě)到一個(gè)文件里,那么整個(gè)路由文件就會(huì)變得像上面那個(gè)例子一樣,變得又亂又長(zhǎng)。

今天介紹兩個(gè)步驟讓我們能把項(xiàng)目路由分模塊管理起來(lái)。本節(jié)內(nèi)容節(jié)選自我的專(zhuān)欄《Go項(xiàng)目搭建和整潔開(kāi)發(fā)實(shí)戰(zhàn)》

項(xiàng)目中怎么規(guī)劃和管理路由

首先根據(jù)我們上一節(jié) 「Go 項(xiàng)目怎么做好分層架構(gòu)和目錄規(guī)劃」中設(shè)計(jì)的項(xiàng)目目錄結(jié)構(gòu),在A(yíng)PI處理器對(duì)應(yīng)的api目錄下的controler和router子目錄中分別存放每個(gè)模塊對(duì)應(yīng)的Api handler 和 router 文件。

舉例來(lái)說(shuō),假設(shè)我們項(xiàng)目中想在有用戶(hù)和訂單兩個(gè)模塊,那么此時(shí)項(xiàng)目的api/controller 和 api/router 中應(yīng)該分別有倆個(gè)文件與業(yè)務(wù)模塊對(duì)應(yīng)。

.
|---api # API 處理器模塊
| |---controller # 控制器
| | |---order.go # 訂單模塊的 Api Handler
| | |---user.go # 用戶(hù)模塊的 Api Handler
| |---router # 路由
| | |---order.go # 訂單模塊的路由文件
| | |---router.go # 負(fù)責(zé)路由初始化和注冊(cè)各模塊路由的總文件
| | |---user.go # 用戶(hù)模塊的路由文件

在路由目錄中 router.go 負(fù)責(zé)路由初始化和注冊(cè)各模塊路由的總文件,此外一些要全局應(yīng)用的中間件也會(huì)在這里設(shè)置,比如像下面這樣。

而進(jìn)入到每個(gè)模塊的路由文件中,首先其路由組設(shè)置的路由前綴要跟模塊名保持統(tǒng)一,另外還可以根據(jù)該模塊中接口的統(tǒng)一特征在路由組上應(yīng)用中間件。

比如是訂單模塊的接口,那么路由組的前綴可以設(shè)置成”/order/”這樣所有訂單相關(guān)的接口都在這個(gè)路徑下,因?yàn)橛脩?hù)只能看自己的訂單,所以所有訂單相關(guān)的接口都需要用戶(hù)認(rèn)證后才能訪(fǎng)問(wèn)。我們可以在路由組上應(yīng)用用戶(hù)認(rèn)證中間件,為組內(nèi)的所有接口增加這項(xiàng)限制,比如像下面這樣。

最后多提一點(diǎn),如果業(yè)務(wù)模塊里的接口太多,像controller/order.go 這樣,單個(gè)文件不好組織整個(gè)模塊的API handler的時(shí)候也可以把其升級(jí)為目錄,變成下面這種結(jié)構(gòu)。

.
|---api # API 處理器模塊
| |---controller # 控制器
| | |---order # 訂單模塊的 Api Handler
| | | |---xxx.go
| | | |---yyy.go
| |---router # 路由
......

好了,介紹完Web項(xiàng)目管理路由的大概思路后,我?guī)Т蠹乙黄鹂聪拢趺从眠@個(gè)思路在Gin項(xiàng)目中分模塊管理

用Gin實(shí)現(xiàn)路由的分模塊管理

分模塊首先就是按照URI的目錄或者叫路由組進(jìn)行管理,首先我們?cè)陧?xiàng)目的 api/router 目錄下定義一個(gè)router.go文件,它負(fù)責(zé)路由初始化和注冊(cè)各模塊的路由。

在其中增加如下代碼:

func RegisterRoutes(engine *gin.Engine) {
// use global middlewares
engine.Use(middleware.StartTrace(), middleware.LogAccess(), middleware.GinPanicRecovery())
routeGroup := engine.Group("")
registerBuildingRoutes(routeGroup)
}

在這里我們先把所有全局中間件應(yīng)用上,Gin框架的路由組是靠 gin.Group 來(lái)維護(hù)的,我們先在全局的router方法中通過(guò) engine.Group(“”) 拿到一個(gè)不帶任何路由前綴的 gin.Group 作為頂級(jí)路由組。

之后再把它傳遞給每個(gè)子模塊的路由注冊(cè)方法,在這個(gè)頂級(jí)路由組的基礎(chǔ)上再去生成各個(gè)路由模塊的路由組對(duì)象,用來(lái)注冊(cè)它們各自的路由。

我們先把之前搭建框架時(shí)寫(xiě)的那些測(cè)試方法的路由都放在api/router/building.go 文件中,所有路由都以”/building/”作為前綴。

// 存放一些項(xiàng)目搭建過(guò)程中驗(yàn)證效果用的接口的路由

func registerBuildingRoutes(rg *gin.RouterGroup) {
// 這個(gè)路由組中的路由都以 /building 開(kāi)頭
g := rg.Group("/building/")
// 測(cè)試 Ping
g.GET("ping", controller.TestPing)
// 測(cè)試日志文件的讀取
g.GET("config-read", controller.TestConfigRead)
// 測(cè)試日志門(mén)面Logger的使用
g.GET("logger-test", controller.TestLogger)
// 測(cè)試服務(wù)的訪(fǎng)問(wèn)日志
g.POST("access-log-test", controller.TestAccessLog)
// 測(cè)試服務(wù)的崩潰日志
g.GET("panic-log-test", controller.TestPanicLog)
// 測(cè)試項(xiàng)目自定義的AppError 打印錯(cuò)誤鏈條和錯(cuò)誤發(fā)生位置
g.GET("customized-error-test", controller.TestAppError)
// 測(cè)試統(tǒng)一響應(yīng)--返回對(duì)象數(shù)據(jù)
g.GET("response-obj", controller.TestResponseObj)
// 測(cè)試統(tǒng)一響應(yīng)--返回列表和分頁(yè)
g.GET("response-list", controller.TestResponseList)
// 測(cè)試統(tǒng)一響應(yīng)--返回錯(cuò)誤
g.GET("response-error", controller.TestResponseError)
}

相應(yīng)的路由對(duì)應(yīng)的API Handler也需要從main.go 中挪到 controller 包中, 我們?cè)赼pi/controller中新建building.go 用來(lái)存放搭建框架過(guò)程中編寫(xiě)的那些測(cè)試接口的Handler方法。

把已有的Controller挪到對(duì)應(yīng)的文件后,可以隨機(jī)抽查幾個(gè)看看看到這些接口是否都還能正常訪(fǎng)問(wèn),接下來(lái)再觀(guān)察下我們請(qǐng)求接口時(shí)產(chǎn)生的應(yīng)用日志。

應(yīng)用日志仍然是能正常的把請(qǐng)求的訪(fǎng)問(wèn)日志和錯(cuò)誤響應(yīng)日志都給記錄下來(lái),證明代碼改動(dòng)沒(méi)問(wèn)題。

路由分模塊管理的規(guī)則

上面我演示了為了做路由分模塊管理在項(xiàng)目中做的那些基礎(chǔ)工作,未來(lái)進(jìn)入需求開(kāi)發(fā)階段我們只要按照這個(gè)規(guī)則分模塊去管理路由就行啦。

后面我們?cè)陧?xiàng)目開(kāi)發(fā)時(shí),API的路由管理也遵循這個(gè)原則:

如果按照我們上節(jié)課「Go 項(xiàng)目怎么做好分層架構(gòu)和目錄規(guī)劃」中介紹的使用應(yīng)用服務(wù)和領(lǐng)域服務(wù)拆分邏輯的方式。控制器層應(yīng)該每個(gè)Controller 方法的代碼都很少,Controller中的代碼不會(huì)太臃腫,除非某個(gè)模塊下接口數(shù)量特別多才需要多個(gè)controller文件來(lái)存放模塊下的Controller代碼。

本文章轉(zhuǎn)載微信公眾號(hào)@網(wǎng)管叨bi叨

上一篇:

深入解密Elasticsearch查詢(xún)優(yōu)化:巧用Profile工具/API提升性能

下一篇:

沒(méi)想到一個(gè) HTTP Client 居然考慮這么多場(chǎng)景
#你可能也喜歡這些API文章!

我們有何不同?

API服務(wù)商零注冊(cè)

多API并行試用

數(shù)據(jù)驅(qū)動(dòng)選型,提升決策效率

查看全部API→
??

熱門(mén)場(chǎng)景實(shí)測(cè),選對(duì)API

#AI文本生成大模型API

對(duì)比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力

25個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)

#AI深度推理大模型API

對(duì)比大模型API的邏輯推理準(zhǔn)確性、分析深度、可視化建議合理性

10個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)