素敵なサムシングを独断と偏見で一方的に紹介するブログ(´・ω・`)

IT

投稿日: 2020年2月25日
最終更新日:

【bindFromRequestData】playFramework2.7で配列をマッピングする方法【BeanValidator】

Anker PowerCor

created by Rinker
Anker
¥4,990 (2024/04/03 21:42:08時点 Amazon調べ-詳細)

旅行には必須の大容量モバイルバッテリー!

ペヤング ソースやきそば 120g×18個

created by Rinker
ペヤング
¥2,600 (2024/04/03 21:42:16時点 Amazon調べ-詳細)

とりあえず保存食として買っておけば間違いなし!

レッドブル エナジードリンク 250ml×24本

created by Rinker
Red Bull(レッドブル)
¥4,000 (2024/04/03 21:42:12時点 Amazon調べ-詳細)

翼を授けよう!

モンスターエナジー 355ml×24本 [エナジードリンク]

created by Rinker
モンスター
¥4,748 (2024/04/03 21:33:15時点 Amazon調べ-詳細)

脳を活性化させるにはこれ!

BANDAI SPIRITS ULTIMAGEAR 遊戯王 千年パズル 1/1スケール

created by Rinker
BANDAI SPIRITS(バンダイ スピリッツ)
¥7,500 (2024/04/03 21:42:14時点 Amazon調べ-詳細)

もう一人の僕を呼び覚ませ!!

MOFT X 【新型 ミニマム版】 iPhone対応 スマホスタンド

created by Rinker
MOFT
¥2,880 (2024/04/03 21:42:18時点 Amazon調べ-詳細)

Amazon一番人気のスマホスタンド!カード類も収納出来てかさ張らないのでオススメです!

サンディスク microSD 128GB

スマホからSwitchまで使える大容量MicroSDカード!

スポンサーリンク

336×280




配列クエリをFormモデルにバインドしようとしたら一癖あった話

PlayFrameworkを使ってAPI開発をしている際に、配列を想定しているクエリパラメーターに対してもBeanバリデーションを行いたかったため、Formモデルを使ってマッピングしようとしたところ、最初の要素しかListモデルにマッピング出来ませんでした。

今回はその原因と実際に試してみた対処方法についてご紹介しようと思います。

手順

前提

以下のようなidを複数指定して返却するようなAPIがあったとします。

まずはModelにマッピングせずに直接取得する方法

まずはController側で直接配列のクエリパラメーターを受け取ってみましょう。

以下のようなroutesの記述とControllerがあったとします。

確認

この場合idsの値は、http://localhost:9000/v1/accounts?ids=1&ids=4&ids=6の場合はids146http://localhost:9000/v1/accounts?ids=1の場合は1http://localhost:9000/v1/accountsの場合はidsempty(nullではない)となります。

しっかりマッピング出来てますね♪

Formモデルで取得

しかし、routesControllerの引数に直接追加すると、クエリパラメーターが増えたりした際の修正範囲が増えてしまいます。

PlayFrameworkのFormはPOSTなどのリクエストボディのマッピングで主に使うようですがGETのクエリパラメーターに対してもモデルにマッピングし、さらにBeanバリデーションを活用したいので試してみましょう。

以下の検索モデルを用意します。

今回はとりあえずなにかしらのBeanバリデーションをかけたいので、@Sizeを利用し要素が4件以上指定された場合にバリデーションエラーを発生させるようにしてみます。

routesControllerは以下のように修正します。

確認

では、実際にリクエストしてみましょう。

まず、http://localhost:9000/v1/accountsの場合はids=nullとなります。この場合はControllerの引数で直接取得する場合との差異が出てますね。

次にhttp://localhost:9000/v1/accounts?ids=1の場合。

こちらは正しくListの要素として4要素がマッピングされていますね。

最後に複数クエリパラメーターが指定されたhttp://localhost:9000/v1/accounts?ids=1&ids=4&ids=8&ids=10の場合です。

あら、一つ目の要素しかマッピングされていませんし、Beanバリデーターも機能していませんね。。。

試しにCriteriaモデルのidsの型をListから配列にしてもダメでした。orz

配列をマッピングしたい場合は[]を付けるのがplayのお作法

実は、PlayFrameworkでは配列パラメーターをマッピングしたい場合は[]を付けるのが基本となっているようです。

試しに、http://localhost:9000/v1/accounts?ids[]=1&ids[]=4&ids[]=8&ids[]=10でリクエストしてみましょう。

正しくids4要素マッピングされ、Beanバリデーションも実行されていますね!

とはいえ、[]を付けるのはちょっと気持ち悪い。。。

しかし、クエリパラメーターに[]を付けるのはちょっと一般的ではない気がするのと、呼び出し側も修正しないといけないのでちょっと採用したくない案ですよね。。。

そこで、クエリには[]をつけずにFormでバインドしてBeanバリデーションを実行する方法を以下のようにして実現してみました!(もっとスマートな方法があるかもしれません。orz)

配列を[]を使わずにFormモデルにbind&Beanバリデーションを実行する方法

routesの修正

まず、routesの設定として配列になりうる要素のみControllerの引数で取得出来るようにします。

この際に、Stringで定義しておくことがポイントです。

ControllerでFormにbindする部分を修正

次に、Controllerの引数で受け取った配列を利用して意図的にバインドする処理を追加します。

確認

では、http://localhost:9000/v1/accounts?ids=1&ids=4&ids=8&ids=10にアクセスして確認してみましょう。

これで一応期待通りの動きになりましたね!

終わりに

痒いところに手が届かない部分を自前でカスタマイズしてみました。

他にも良い対応策があると思いますが、同じようにモヤモヤしている方は参考にしてみていただければなと思います。

336×280




336×280




CATEGORIES & TAGS

IT, , , , , , , , ,

blogenist

Author: blogenist

関連記事

YouTubeも見てね♪

お名前.comサイドバー