※あくまでカモネギ用の備忘録なので、記述を簡素化する過程でミス等ありましたらすみません😭
適切なAPI定義の場合
パラメータならびにリクエストボディ
- パスパラメータ : param1, param2
- クエリパラメータ : param3
- リクエストボディ : contents(配列)
curl例
curl -X 'POST' -i \
'http://example.com/path/param1/param2?query=param3' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"contents": [
{
"value1": "値10",
"list1": ["リスト11","リスト12"]
},
{
"value1": "値20",
"list1": ["リスト21","リスト22","リスト23"]
}
]
}'
リクエストを構造体に変換
type handler struct {}
type Request struct {
Param1 string `param:"param1" validate:"required"`
Param2 string `param:"param2" validate:"required"`
Param3 string `query:"param3" validate:"required"`
Contents []Content `json:"contents"`
}
type Content struct {
Value1 string `json:"value1" validate:"required"`
List1 []string `json:"list1" validate:"required"
}
func (h *handler) Handle(ctx echo.Context) error {
// リクエストをシンプルにバインドすればOK。
request := &Request{}
if err := ctx.Bind(request); err != nil {
return err
}
if err := ctx.Validate(request); err != nil {
return err
}
...
}
Bind1回で構造体に変換できるので楽ちん。
やや難ありなAPI定義の場合
パラメータならびにリクエストボディ
- パスパラメータ : param1, param2
- クエリパラメータ : param3
- リクエストボディ : 配列(key無し)
難ありな点は、リクエストボディの配列に名前が付いていない点です。
上記の適切なAPI定義とは異なり、”contents”が付与されていません。
curl例
curl -X 'POST' -i \
'http://example.com/path/param1/param2?query=param3' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '[
{
"value1": "値10",
"list1": ["リスト11","リスト12"]
},
{
"value1": "値20",
"list1": ["リスト21","リスト22","リスト23"]
}
]'
リクエストを構造体に変換
type handler struct {}
type Request struct {
Param1 string `param:"param1" validate:"required"`
Param2 string `param:"param2" validate:"required"`
Param3 string `query:"param3" validate:"required"`
}
type Contents []Content
type Content struct {
Value1 string `json:"value1" validate:"required"`
List1 []string `json:"list1" validate:"required"`
}
-----
func (h *handler) Handle(ctx echo.Context) error {
// リクエストボディの(配列)にkeyがないので、
// Bind関数内で配列も含めたjson.Unmarshalができないため、
// パスパラメータとクエリパラメータを各々取得する。
param1 := ctx.Param("param1")
param2 := ctx.Param("param2")
param3 := ctx.QueryParam("param3")
if param1 == "" || param2 == "" || param3 == "" {
// 必要に応じてエラー処理
}
// リクエストボディをバインド
contents := Contents{}
if err := ctx.Bind(&contents); err != nil {
return err
}
for _, content := range contents {
if err := ctx.Validate(content); err != nil {
return err
}
}
...
}
所感
意図的でないのであれば、API定義にてリクエストボディの配列に名前が付けた方が、
- サーバサイドの実装がシンプルにできる。
- フロントエンド・サーバサイド共に、配列が何を表しているのが理解しやすい。
と思いました。
参考資料
- Echoの各ドキュメント(特に以下)
- その他、「echo 配列 bind」などでググると良い感じの記事が出てくるかもです。
以上
リンク
リンク