所有文章 > API使用场景 > Go项目实战-API路由的分模块管理
Go项目实战-API路由的分模块管理

Go项目实战-API路由的分模块管理

随着项目开发的迭代,我们写的接口往往会越来越多,如果都把API的路由写到一个文件里,那么整个路由文件就会变得又乱又长,所以我们最好在项目开始阶段就给路由的分模块管理做好规划。

今天这个文章给大家介绍一下Web项目API路由的分模块管理,我们的项目使用的是Gin框架,但基本上所有的Web框架都能按照这个方式来分模块管理API接口的路由。

一些路由管理混乱的例子

首先,我先给大家看一个曾经维护过的项目的路由文件 router.go, 这个项目用的也是Gin框架,整个文件里500多行全是API接口的路由。

你说这么写不好维护吧,全项目的路由都在这里不用其他地方找,按能用就行的标准,确实是能用。

而且Gin的官方文档里在路由这块的例子确实也是这么写的。

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

// 简单的路由组: v1
v1 := router.Group("/v1")
{
v1.POST("/login", loginEndpoint)
v1.POST("/submit", submitEndpoint)
v1.POST("/read", readEndpoint)
}

// 简单的路由组: v2
v2 := router.Group("/v2")
{
v2.POST("/login", loginEndpoint)
v2.POST("/submit", submitEndpoint)
v2.POST("/read", readEndpoint)
}

router.Run(":8080")
}

随着项目开发的迭代,我们写的接口往往会越来越多,如果还按上面这样把API的路由写到一个文件里,那么整个路由文件就会变得像上面那个例子一样,变得又乱又长。

今天介绍两个步骤让我们能把项目路由分模块管理起来。本节内容节选自我的专栏《Go项目搭建和整洁开发实战》

项目中怎么规划和管理路由

首先根据我们上一节 「Go 项目怎么做好分层架构和目录规划」中设计的项目目录结构,在API处理器对应的api目录下的controler和router子目录中分别存放每个模块对应的Api handler 和 router 文件。

举例来说,假设我们项目中想在有用户和订单两个模块,那么此时项目的api/controller 和 api/router 中应该分别有俩个文件与业务模块对应。

.
|---api # API 处理器模块
| |---controller # 控制器
| | |---order.go # 订单模块的 Api Handler
| | |---user.go # 用户模块的 Api Handler
| |---router # 路由
| | |---order.go # 订单模块的路由文件
| | |---router.go # 负责路由初始化和注册各模块路由的总文件
| | |---user.go # 用户模块的路由文件

在路由目录中 router.go 负责路由初始化和注册各模块路由的总文件,此外一些要全局应用的中间件也会在这里设置,比如像下面这样。

而进入到每个模块的路由文件中,首先其路由组设置的路由前缀要跟模块名保持统一,另外还可以根据该模块中接口的统一特征在路由组上应用中间件。

比如是订单模块的接口,那么路由组的前缀可以设置成”/order/”这样所有订单相关的接口都在这个路径下,因为用户只能看自己的订单,所以所有订单相关的接口都需要用户认证后才能访问。我们可以在路由组上应用用户认证中间件,为组内的所有接口增加这项限制,比如像下面这样。

最后多提一点,如果业务模块里的接口太多,像controller/order.go 这样,单个文件不好组织整个模块的API handler的时候也可以把其升级为目录,变成下面这种结构。

.
|---api # API 处理器模块
| |---controller # 控制器
| | |---order # 订单模块的 Api Handler
| | | |---xxx.go
| | | |---yyy.go
| |---router # 路由
......

好了,介绍完Web项目管理路由的大概思路后,我带大家一起看下,怎么用这个思路在Gin项目中分模块管理

用Gin实现路由的分模块管理

分模块首先就是按照URI的目录或者叫路由组进行管理,首先我们在项目的 api/router 目录下定义一个router.go文件,它负责路由初始化和注册各模块的路由。

在其中增加如下代码:

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

在这里我们先把所有全局中间件应用上,Gin框架的路由组是靠 gin.Group 来维护的,我们先在全局的router方法中通过 engine.Group(“”) 拿到一个不带任何路由前缀的 gin.Group 作为顶级路由组。

之后再把它传递给每个子模块的路由注册方法,在这个顶级路由组的基础上再去生成各个路由模块的路由组对象,用来注册它们各自的路由。

我们先把之前搭建框架时写的那些测试方法的路由都放在api/router/building.go 文件中,所有路由都以”/building/”作为前缀。

// 存放一些项目搭建过程中验证效果用的接口的路由

func registerBuildingRoutes(rg *gin.RouterGroup) {
// 这个路由组中的路由都以 /building 开头
g := rg.Group("/building/")
// 测试 Ping
g.GET("ping", controller.TestPing)
// 测试日志文件的读取
g.GET("config-read", controller.TestConfigRead)
// 测试日志门面Logger的使用
g.GET("logger-test", controller.TestLogger)
// 测试服务的访问日志
g.POST("access-log-test", controller.TestAccessLog)
// 测试服务的崩溃日志
g.GET("panic-log-test", controller.TestPanicLog)
// 测试项目自定义的AppError 打印错误链条和错误发生位置
g.GET("customized-error-test", controller.TestAppError)
// 测试统一响应--返回对象数据
g.GET("response-obj", controller.TestResponseObj)
// 测试统一响应--返回列表和分页
g.GET("response-list", controller.TestResponseList)
// 测试统一响应--返回错误
g.GET("response-error", controller.TestResponseError)
}

相应的路由对应的API Handler也需要从main.go 中挪到 controller 包中, 我们在api/controller中新建building.go 用来存放搭建框架过程中编写的那些测试接口的Handler方法。

把已有的Controller挪到对应的文件后,可以随机抽查几个看看看到这些接口是否都还能正常访问,接下来再观察下我们请求接口时产生的应用日志。

应用日志仍然是能正常的把请求的访问日志和错误响应日志都给记录下来,证明代码改动没问题。

路由分模块管理的规则

上面我演示了为了做路由分模块管理在项目中做的那些基础工作,未来进入需求开发阶段我们只要按照这个规则分模块去管理路由就行啦。

后面我们在项目开发时,API的路由管理也遵循这个原则:

  • 每个业务模块的API,都编写单独的路由注册函数,把路由放在api/router/目录的一个单独的文件中,文件名与模块名相对应。
  • 每个业务模块的API Handler,都放在api/controller 目录下的一个单独文件或者单独的目录中。

如果按照我们上节课「Go 项目怎么做好分层架构和目录规划」中介绍的使用应用服务和领域服务拆分逻辑的方式。控制器层应该每个Controller 方法的代码都很少,Controller中的代码不会太臃肿,除非某个模块下接口数量特别多才需要多个controller文件来存放模块下的Controller代码。

本文章转载微信公众号@网管叨bi叨

#你可能也喜欢这些API文章!