EchoMiddleCoding
Как реализовать версионирование API в Echo?
Версионирование API в Echo реализуется через группы маршрутов с префиксом /v1, /v2 либо через заголовок Accept или кастомный middleware, разбрасывающий запросы по хендлерам нужной версии.
Версионирование API в Echo
Существует три распространённых подхода: версия в URL-пути, версия в заголовке Accept и версия в пользовательском заголовке (X-API-Version). Echo хорошо поддерживает все три благодаря группам маршрутов и middleware.
1. Версия в пути (наиболее популярный вариант)
package main
import (
"net/http"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
)
func main() {
e := echo.New()
e.Use(middleware.Logger())
e.Use(middleware.Recover())
// Группа v1
v1 := e.Group("/v1")
v1.GET("/users", listUsersV1)
v1.POST("/users", createUserV1)
// Группа v2 — расширенный контракт
v2 := e.Group("/v2")
v2.GET("/users", listUsersV2)
v2.POST("/users", createUserV2)
v2.DELETE("/users/:id", deleteUserV2)
e.Logger.Fatal(e.Start(":8080"))
}
func listUsersV1(c echo.Context) error {
return c.JSON(http.StatusOK, map[string]string{"version": "v1"})
}
func listUsersV2(c echo.Context) error {
return c.JSON(http.StatusOK, map[string]string{"version": "v2", "extra": "field"})
}
func createUserV1(c echo.Context) error { return c.NoContent(http.StatusCreated) }
func createUserV2(c echo.Context) error { return c.NoContent(http.StatusCreated) }
func deleteUserV2(c echo.Context) error { return c.NoContent(http.StatusNoContent) }
2. Версия через заголовок Accept
Клиент присылает Accept: application/vnd.myapp.v2+json. Middleware парсит значение и кладёт версию в контекст:
func versionMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
accept := c.Request().Header.Get("Accept")
version := "v1" // default
if strings.Contains(accept, "v2") {
version = "v2"
}
c.Set("api_version", version)
return next(c)
}
}
// Регистрация:
e.Use(versionMiddleware)
// В хендлере:
func getUser(c echo.Context) error {
version := c.Get("api_version").(string)
if version == "v2" {
return c.JSON(http.StatusOK, UserV2{})
}
return c.JSON(http.StatusOK, UserV1{})
}
3. Выделение версий в отдельные пакеты
При большом API удобно держать хендлеры в пакетах handlers/v1 и handlers/v2, а регистрацию маршрутов — в router/router.go:
// router/router.go
package router
import (
v1 "myapp/handlers/v1"
v2 "myapp/handlers/v2"
"github.com/labstack/echo/v4"
)
func Register(e *echo.Echo) {
g1 := e.Group("/v1")
g1.GET("/users", v1.ListUsers)
g2 := e.Group("/v2")
g2.GET("/users", v2.ListUsers)
}
Рекомендации
- Добавляйте заголовок
Deprecation: trueиSunset: Sat, 01 Jan 2027 00:00:00 GMTдля устаревших версий. - Документируйте каждую версию отдельно в Swagger/OpenAPI через теги.
- Не удаляйте старую версию без явного уведомления потребителей.
Подводные камни
- Дублирование кода между версиями — выносите общую логику в сервисный слой, а хендлеры пусть занимаются только преобразованием контракта.
- Забытые маршруты: при добавлении нового эндпоинта легко добавить его только в v2 и забыть задокументировать, что в v1 его нет.
- Несовместимые изменения в middleware, применённых к
eглобально, — они затрагивают все версии одновременно; версионные middleware вешайте на группу. - Версия в заголовке
Acceptплохо кешируется CDN безVary: Accept. - Бесконечное накопление версий: v1, v2, v3... — устанавливайте политику deprecation и придерживайтесь её.
- При URL-версионировании PUT/PATCH-запросы могут неожиданно попасть не в ту группу, если клиент перепутал базовый путь.
- Отсутствие интеграционных тестов на каждую версию отдельно — регрессии в старых версиях остаются незамеченными.
Common mistakes
- Давать ответ про версионирование API в Echo только на уровне определения, не показывая поведение в реальном приложении.
- Игнорировать границы ответственности вокруг темы «версионирование API в Echo»: кто отменяет работу, кто владеет ресурсом и где формируется ответ клиенту.
- Не связывать версионирование API в Echo с observability, тестированием или безопасностью, когда это влияет на продакшен-поведение.
What the interviewer is testing
- Точно объясняет, что именно делает версионирование API в Echo и где это используется в Go-коде.
- Связывает версионирование API в Echo с корректным lifecycle запроса, отменой, конкурентностью или конфигурацией сервера там, где это уместно.
- Не изобретает API и опирается на реальные контракты официальной документации.