В чём разница между c.Param(), c.QueryParam() и c.FormValue() в Echo?
c.Param() читает path-сегменты (:id), c.QueryParam() — строку запроса (?key=), c.FormValue() — тело application/x-www-form-urlencoded или multipart/form-data.
Три источника входных данных в Echo
Echo предоставляет три метода для чтения параметров из разных частей HTTP-запроса. Важно понимать, откуда берётся каждый тип данных.
c.Param() — параметры пути
Читает именованные сегменты URL, объявленные в маршруте с префиксом :. Если сегмент не найден, возвращает пустую строку.
// Маршрут: /users/:id/posts/:postID
e.GET("/users/:id/posts/:postID", func(c echo.Context) error {
userID := c.Param("id") // из /users/42/posts/7 → "42"
postID := c.Param("postID") // → "7"
return c.JSON(http.StatusOK, map[string]string{
"user_id": userID,
"post_id": postID,
})
})
Wildcard-параметр * читается через c.Param("*"):
e.GET("/static/*", func(c echo.Context) error {
path := c.Param("*") // /static/css/main.css → "css/main.css"
return c.File("public/" + path)
})
c.QueryParam() — параметры строки запроса
Читает значение из query string (часть URL после ?). Если параметр отсутствует, возвращает пустую строку.
// GET /search?q=golang&page=2&limit=10
e.GET("/search", func(c echo.Context) error {
q := c.QueryParam("q") // "golang"
page := c.QueryParam("page") // "2"
limit := c.QueryParam("limit") // "10"
missing := c.QueryParam("x") // ""
// Все параметры сразу
allParams := c.QueryParams() // url.Values
return c.JSON(http.StatusOK, map[string]string{
"q": q,
"page": page,
"limit": limit,
})
})
c.FormValue() — данные формы
Читает значение из тела запроса типа application/x-www-form-urlencoded или multipart/form-data. Под капотом вызывает r.FormValue() из стандартной библиотеки, которая автоматически парсит тело.
// POST /login с телом: username=admin&password=secret
e.POST("/login", func(c echo.Context) error {
username := c.FormValue("username") // "admin"
password := c.FormValue("password") // "secret"
if username == "" || password == "" {
return echo.NewHTTPError(http.StatusBadRequest, "username and password required")
}
return c.JSON(http.StatusOK, map[string]string{"user": username})
})
Комбинированный пример
// PUT /users/:id?notify=true + body: reason=vacation
e.PUT("/users/:id", func(c echo.Context) error {
id := c.Param("id") // path param
notify := c.QueryParam("notify") // query string
reason := c.FormValue("reason") // form body
return c.JSON(http.StatusOK, map[string]string{
"id": id,
"notify": notify,
"reason": reason,
})
})
Подводные камни
- Нет автоматического преобразования типов: все три метода возвращают
string. Для числовых значений используйтеstrconv.Atoi()или методc.Bind()для автоматического маппинга. - FormValue поглощает тело: после вызова
c.FormValue()тело запроса уже прочитано — нельзя повторно вызватьc.Bind()для JSON-тела. - QueryParam не декодирует массивы: для
?tags=go&tags=pythonиспользуйтеc.QueryParams()["tags"], а неc.QueryParam("tags")— последний вернёт только первое значение. - Param возвращает URL-decoded значение:
%20в пути преобразуется в пробел автоматически. - FormValue работает только с form-encoded телом: для JSON-тела используйте
c.Bind()или читайте тело вручную черезc.Request().Body. - Отсутствие валидации: ни один из методов не валидирует данные — всегда проверяйте входные значения перед использованием.
Common mistakes
- Давать ответ про Param, QueryParam и FormValue в Echo только на уровне определения, не показывая поведение в реальном приложении.
- Игнорировать границы ответственности вокруг темы «Param, QueryParam и FormValue в Echo»: кто отменяет работу, кто владеет ресурсом и где формируется ответ клиенту.
- Не связывать Param, QueryParam и FormValue в Echo с observability, тестированием или безопасностью, когда это влияет на продакшен-поведение.
What the interviewer is testing
- Точно объясняет, что именно делает Param, QueryParam и FormValue в Echo и где это используется в Go-коде.
- Связывает Param, QueryParam и FormValue в Echo с корректным lifecycle запроса, отменой, конкурентностью или конфигурацией сервера там, где это уместно.
- Не изобретает API и опирается на реальные контракты официальной документации.