GinJuniorCoding

Как работают группы маршрутов в Gin и каковы их сценарии использования?

Группы маршрутов в Gin создаются через r.Group("/prefix", middleware...) и объединяют маршруты с общим URL-префиксом и middleware. Основные сценарии: версионирование API (/api/v1, /api/v2) и разделение публичных и приватных эндпоинтов.

Группы маршрутов в Gin

Группа маршрутов (RouterGroup) позволяет объединять маршруты с общим префиксом пути и/или общим набором middleware. Это ключевой инструмент для структурирования API.

Базовый синтаксис

package main

import (
	"net/http"

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

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

	// Группа /api/v1
	v1 := r.Group("/api/v1")
	{
		v1.GET("/users", listUsers)       // GET /api/v1/users
		v1.POST("/users", createUser)     // POST /api/v1/users
		v1.GET("/users/:id", getUser)     // GET /api/v1/users/:id
		v1.PUT("/users/:id", updateUser)  // PUT /api/v1/users/:id
		v1.DELETE("/users/:id", deleteUser) // DELETE /api/v1/users/:id
	}

	// Группа /api/v2
	v2 := r.Group("/api/v2")
	{
		v2.GET("/users", listUsersV2)
	}

	r.Run(":8080")
}

Middleware на уровне группы

Middleware, переданный в Group(), применяется только к маршрутам этой группы:

func AuthRequired() gin.HandlerFunc {
	return func(c *gin.Context) {
		token := c.GetHeader("Authorization")
		if token == "" {
			c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{
				"error": "unauthorized",
			})
			return
		}
		c.Next()
	}
}

func main() {
	r := gin.New()
	r.Use(gin.Recovery())

	// Публичные маршруты — без аутентификации
	public := r.Group("/")
	{
		public.POST("/login", loginHandler)
		public.GET("/health", healthHandler)
	}

	// Приватные маршруты — требуют токен
	private := r.Group("/api", AuthRequired())
	{
		private.GET("/profile", profileHandler)
		private.POST("/orders", createOrderHandler)
	}

	r.Run(":8080")
}

Вложенные группы

Группы можно вкладывать друг в друга для более детальной структуры:

admin := r.Group("/admin", AuthRequired(), AdminOnly())
{
	users := admin.Group("/users")
	{
		users.GET("/", listAdminUsers)       // GET /admin/users/
		users.DELETE("/:id", deleteUser)     // DELETE /admin/users/:id
	}

	posts := admin.Group("/posts")
	{
		posts.GET("/", listAdminPosts)       // GET /admin/posts/
		posts.POST("/", createPost)          // POST /admin/posts/
	}
}

Группы для версионирования API

func RegisterV1Routes(rg *gin.RouterGroup) {
	rg.GET("/products", listProductsV1)
	rg.GET("/products/:id", getProductV1)
}

func RegisterV2Routes(rg *gin.RouterGroup) {
	rg.GET("/products", listProductsV2) // другая пагинация/формат
	rg.GET("/products/:id", getProductV2)
}

func main() {
	r := gin.Default()
	RegisterV1Routes(r.Group("/api/v1"))
	RegisterV2Routes(r.Group("/api/v2"))
	r.Run(":8080")
}

Подводные камни

  • Фигурные скобки — только для читаемости. Синтаксис v1 := r.Group(...) { ... } — это обычный блок Go, не обязательный. Маршруты можно регистрировать без блока.
  • Middleware группы не наследуется автоматически вложенными группами. При вызове admin.Group("/users") middleware AdminOnly() НЕ передаётся в подгруппу — нужно явно передавать или добавлять через subgroup.Use().
  • Нельзя добавить middleware к группе после регистрации маршрутов. Вызов group.Use(mw) после group.GET(...) не применит middleware к уже зарегистрированным маршрутам.
  • Конфликты префиксов. Маршруты /api в одной группе и /api/v1 в другой не конфликтуют, но /api/:version и /api/v1 вызовут панику при регистрации.
  • Порядок middleware в глобальном Use() vs группового. Глобальные middleware (r.Use()) выполняются до групповых. Учитывайте это при проектировании цепочки аутентификации.
  • Пустой префикс группы. r.Group("") создаёт группу без добавления к пути — используется исключительно для применения middleware без изменения структуры URL.

Common mistakes

  • Давать ответ про groups маршрутов в Gin только на уровне определения, не показывая поведение в реальном приложении.
  • Игнорировать границы ответственности вокруг темы «groups маршрутов в Gin»: кто отменяет работу, кто владеет ресурсом и где формируется ответ клиенту.
  • Не связывать groups маршрутов в Gin с observability, тестированием или безопасностью, когда это влияет на продакшен-поведение.

What the interviewer is testing

  • Точно объясняет, что именно делает groups маршрутов в Gin и где это используется в Go-коде.
  • Связывает groups маршрутов в Gin с корректным lifecycle запроса, отменой, конкурентностью или конфигурацией сервера там, где это уместно.
  • Не изобретает API и опирается на реальные контракты официальной документации.

Sources

Related topics