【Go】Echoによる構造体タグの使い方まとめ|query・param・form・json・xml のバインド方法
はじめに
Echoでは、主にjson
タグを使うことが多いですが、他にも複数のタグがサポートされています。
本記事では、それぞれのタグの使い方を備忘録として整理します!
📝この記事でわかること
-
EchoのBind()と各種タグの役割
Echoでは、query
・param
・form
・json
・xml
といったタグを構造体に付けることで、リクエストの各種データを自動的にバインドできます。 -
タグがない場合の挙動と注意点
タグを指定しないとバインドが失敗するケースが多く、特にスネークケースのJSONや大文字小文字を区別するXMLでは、正しくフィールドに値が入らないことがあります。 -
リクエスト形式ごとの適切なタグの使い分け
GETにはquery
、URLパスにはparam
、フォームにはform
、JSON APIにはjson
、XML APIにはxml
タグを使うことで、正確なデータ受け取りが可能になります。
query
タグ – クエリパラメータのバインド
🛠️1. query
タグは、GETリクエストのURLに含まれるクエリパラメータを構造体にマッピングします。
使用例
package main
import (
"net/http"
"github.com/labstack/echo/v4"
)
type User struct {
UserID int `query:"user_id"`
Name string `query:"name"`
IsAdmin bool `query:"is_admin"`
}
func main() {
e := echo.New()
e.GET("/user", func(c echo.Context) error {
user := User{}
if err := c.Bind(&user); err != nil {
return c.JSON(http.StatusBadRequest, err)
}
return c.JSON(http.StatusOK, user)
})
e.Logger.Fatal(e.Start(":8080"))
}
実行例と出力
①すべてのクエリパラメータが渡された場合
curl 'http://localhost:8080/user?user_id=1&name=Taro&is_admin=true'
# 出力結果 {"UserID":1,"Name":"Taro","IsAdmin":true}
②一部のクエリパラメータが省略された場合
curl 'http://localhost:8080/user?user_id=1&name=Taro'
# 出力結果 {"UserID":1,"Name":"Taro","IsAdmin":false}
指定されなかったフィールドは、ゼロ値が設定されます。
③タグを指定しなかった場合
curl 'http://localhost:8080/user?user_id=1&name=Taro&is_admin=true'
# 出力結果 {"UserID":0,"Name":"","IsAdmin":false}
タグがないフィールドにはゼロ値が入ります。
param
タグ – パスパラメータのバインド
🛠️2. param
タグは、URLの一部(例: /user/:user_id)を構造体にバインドするために使用します。
使用例
package main
import (
"net/http"
"github.com/labstack/echo/v4"
)
type User struct {
UserID int `param:"user_id"`
}
func main() {
e := echo.New()
e.GET("/user/:user_id", func(c echo.Context) error {
user := User{}
if err := c.Bind(&user); err != nil {
return c.JSON(http.StatusBadRequest, err)
}
return c.JSON(http.StatusOK, user)
})
e.Logger.Fatal(e.Start(":8080"))
}
実行例と出力
①タグを指定した場合
curl 'http://localhost:8080/user/1'
# 出力結果 {"UserID":1}
②タグを指定しなかった場合
curl 'http://localhost:8080/user/1'
# 出力結果 {"UserID":0}
タグがないフィールドにはゼロ値が入ります。
form
タグ – フォーム送信データのバインド
🛠️3. form
タグは、application/x-www-form-urlencoded
やmultipart/form-data
で送信されたボディデータを構造体にマッピングします。
使用例
package main
import (
"net/http"
"github.com/labstack/echo/v4"
)
type User struct {
UserID int `form:"user_id"`
Name string `form:"name"`
IsAdmin bool `form:"is_admin"`
}
func main() {
e := echo.New()
e.POST("", func(c echo.Context) error {
user := User{}
if err := c.Bind(&user); err != nil {
return c.JSON(http.StatusBadRequest, err)
}
return c.JSON(http.StatusOK, user)
})
e.Logger.Fatal(e.Start(":8080"))
}
実行例と出力
①すべてのデータが渡された場合
curl -X POST -H 'Content-Type: application/x-www-form-urlencoded' -d 'user_id=1&name=Taro&is_admin=true' http://localhost:8080
# 出力結果 {"UserID":1,"Name":"Taro","IsAdmin":true}
②一部のデータが省略された場合
curl -X POST -H 'Content-Type: application/x-www-form-urlencoded' -d 'user_id=1&name=Taro' http://localhost:8080
# 出力結果 {"UserID":1,"Name":"Taro","IsAdmin":false}
タグがないフィールドにはゼロ値が入ります。
③タグを指定しなかった場合
curl -X POST -H 'Content-Type: application/x-www-form-urlencoded' -d 'user_id=1&name=Taro&is_admin=true' http://localhost:8080
# 出力結果 {"UserID":0,"Name":"","IsAdmin":false}
タグがないフィールドにはゼロ値が入ります。
json
タグ – JSONリクエストボディのバインド
🛠️4. json
タグは、application/json
のリクエストボディを構造体にマッピングします。
encoding/json
に準拠し、タグがない場合はフィールド名と完全一致しなければバインドされません。
使用例
package main
import (
"net/http"
"github.com/labstack/echo/v4"
)
type User struct {
UserID int `json:"user_id"`
Name string `json:"name"`
IsAdmin bool `json:"is_admin"`
}
func main() {
e := echo.New()
e.POST("", func(c echo.Context) error {
user := User{}
if err := c.Bind(&user); err != nil {
return c.JSON(http.StatusBadRequest, err)
}
return c.JSON(http.StatusOK, user)
})
e.Logger.Fatal(e.Start(":8080"))
}
実行例と出力
①すべてのデータが渡された場合
curl -X POST -H 'Content-Type: application/json' -d '{"user_id":1, "name":"Taro", "is_admin":true}' http://localhost:8080
# 出力結果 {"UserID":1,"Name":"Taro","IsAdmin":true}
②一部のデータが省略された場合
curl -X POST -H 'Content-Type: application/json' -d '{"user_id":1, "name":"Taro"}' http://localhost:8080
# 出力結果 {"UserID":1,"Name":"Taro","IsAdmin":false}
タグがないフィールドにはゼロ値が入ります。
③タグを指定しなかった場合
curl -X POST -H 'Content-Type: application/json' -d '{"user_id":1, "name":"Taro", "is_admin":true}' http://localhost:8080
# 出力結果 {"UserID":0,"Name":"Taro","IsAdmin":false}
この場合、Nameだけがバインドされています。
タグがないと user_id → UserID のようなスネークケースは認識されません。
大文字小文字は無視されるため "Name" → Name へのマッピングは可能です。
xml
タグ – XMLボディのバインド
🛠️5. xml
タグは、application/xml
形式のリクエストボディを構造体にバインドします。
encoding/xml
パッケージと連携して動作します。
使用例
package main
import (
"net/http"
"github.com/labstack/echo/v4"
)
type User struct {
UserID int `xml:"user_id"`
Name string `xml:"name"`
IsAdmin bool `xml:"is_admin"`
}
func main() {
e := echo.New()
e.POST("", func(c echo.Context) error {
user := User{}
if err := c.Bind(&user); err != nil {
return c.JSON(http.StatusBadRequest, err)
}
return c.JSON(http.StatusOK, user)
})
e.Logger.Fatal(e.Start(":8080"))
}
実行例と出力
①すべてのデータが渡された場合
curl -X POST -H 'Content-Type: application/xml' -d '<user><user_id>1</user_id><name>Taro</name><is_admin>true</is_admin></user>' http://localhost:8080
# 出力結果 {"UserID":1,"Name":"Taro","IsAdmin":true}
②一部のデータが省略された場合
curl -X POST -H 'Content-Type: application/xml' -d '<user><user_id>1</user_id><name>Taro</name></user>' http://localhost:8080
# 出力結果 {"UserID":1,"Name":"Taro","IsAdmin":false}
タグがないフィールドにはゼロ値が入ります。
③タグを指定しなかった場合
curl -X POST -H 'Content-Type: application/json' -d '{"user_id":1, "name":"Taro", "is_admin":true}' http://localhost:8080
# 出力結果 {"UserID":0,"Name":"","IsAdmin":false}
XMLはJSONと異なり、大文字・小文字を区別します。
なので例えば以下のように送った場合はNameがバインドされます。
curl -X POST -H 'Content-Type: application/xml' -d '<user><user_id>1</user_id><Name>Taro</Name></user>' http://localhost:8080
# 出力結果{"UserID":0,"Name":"Taro","IsAdmin":false}
✅まとめ
Echoを使ったAPI開発では、構造体へのバインド処理をシンプルにするために、各リクエスト形式に応じたタグの活用が不可欠です。
タグを適切に指定することで、手動での値の抽出や型変換を減らし、保守性と可読性の高いコードが実現できます。
特に以下の点を意識すると、安全かつ効率的に開発が進められます。
- 必ずタグを指定すること(特にjson/xml)
- 形式ごとのデータの違い(大小文字、ケース)に注意すること
- バインドされない=ゼロ値になることを前提にした処理を設計すること
このような知識を踏まえたうえで、EchoのBind()機能を活用すれば、APIの受け口をより堅牢に構築できます。
✏️参考
Discussion