Edited at

【Kotlin】バリデーションの書き方の基礎【SpringBoot】

この記事はMicroAd Advent Calendarの5日目の記事です。


TL;DR

Kotlinでバリデーションをやります。主に書くのは以下2点についてです。


  1. アノテーションを使ったバリデーション

  2. AssertTrueを使ったバリデーション

他の書き方もありますが、とりあえず自分が知っているのがこの2つなのでまとめます。

当初アノテーション自作まで書いてましたが、長くなりすぎたので分割し、7日目に回しました。


前書き

この記事は以下の記事を元に書いています。


コントローラー

コントローラーは以下を用います。

受け取ったmyModelに対してバリデーションを行い、引っかかればエラーを、引っかからなければpostした内容を返しています。


MyController.kt

import com.wrongwrong.modeltest.model.MyModel

import org.springframework.validation.BindingResult
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("my")
class MyController{

@PostMapping
fun myPostTest(
@RequestBody @Validated myModel: MyModel,
bindingResult: BindingResult
): String {
//エラーがあればエラーを文字列にして返す
if(bindingResult.hasErrors()){
return bindingResult.allErrors.toString()
}
//受け取った内容を返却
return "post:" + myModel.toString()
}
}


エラーの無い状態で叩くと以下のようになります。


エラー無し

$ curl -X POST -H "Content-Type: application/json" -d '{"id":1, "name":"wrong wrong", "create":"2018-11-01", "update":"2018-11-02"}' localhost:8080/my

post:MyModel(id=1, name=wrong wrong, create=Thu Nov 01 09:00:00 JST 2018, update=Fri Nov 02 09:00:00 JST 2018)


モデル

今回バリデーションを行う上で、元にするモデルは以下です。

全てNullableとしなければ正常にバリデーションが行えないので、必ずNullableで宣言してください(説明は本題と外れるので省略します)。

バリデーションしたい内容はコメントの通りです。


MyModel.kt

import java.util.*

data class MyModel(
// nullを禁止したい
val id: Long?,
// 名前がスペース区切りになっていることを確認したい
val name: String?,
// createはupdateと同じか過去にしたい
val create: Date?,
val update: Date?
)



アノテーションを使ったバリデーション

まずidのバリデーションを、アノテーションとして実装されたバリデーターを使ってやっていきます。

data classでは、@field:NotNullというようにアノテーションを付与します。

Javaではfield:無しでもバリデーションが行えますが、Data Classではこれを付けなければ正常にバリデーションができません。

アノテーションを付与すると以下のようになります。


MyModel.kt

import java.util.*

import javax.validation.constraints.NotNull

data class MyModel(
@field:NotNull(message = "idはnull不許可")
val id: Long?,
// 名前がスペース区切りになっていることを確認したい
val name: String?,
// createはupdateと同じか過去にしたい
val create: Date?,
val update: Date?
)


この状態でエラー有り/無しをそれぞれCurlで叩いた結果が以下です。


エラー無し

$ curl -X POST -H "Content-Type: application/json" -d '{"id":1}' localhost:8080/my

post:MyModel(id=1, name=null, create=null, update=null)


エラー有り

$ curl -X POST -H "Content-Type: application/json" -d '{}' localhost:8080/my

[Field error in object 'myModel' on field 'id': rejected value [null]; codes [NotNull.myModel.id,NotNull.id,NotNull.java.lang.Long,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [myModel.id,id]; arguments []; default message [id]]; default message [idはnull不許可]]


利用できるアノテーション

javax.validation.constraintsクラスや、org.hibernate.validator.constraintsクラスを見ておくと、既存で利用できるアノテーションは大体まとまっています。

javax.validation.constraints (Java(TM) EE 8 Specification APIs)

org.hibernate.validator.constraints (Hibernate Validator 5.1.3.Final)


AssertTrueを使ったバリデーション

次にcreateとupdateの相関チェックをやっていきます。

相関チェックはJavaと同様、@AssertTrue(または@AssertFalse)を付与したBool型の関数で行います。

今回は相関チェックにのみ利用していますが、アノテーションが用意されていないような単体チェックにも利用できます。

相関チェックを加えると以下のようになります。


MyModel.kt

import java.util.*

import javax.validation.constraints.AssertTrue
import javax.validation.constraints.NotNull

data class MyModel(
@field:NotNull(message = "idはnull不許可")
val id: Long?,
// 名前がスペース区切りになっていることを確認したい
val name: String?,
val create: Date?,
val update: Date?
) {
@AssertTrue(message = "updateがcreateより過去")
fun isLater(): Boolean {
if(create == null || update == null) return true
return create.before(update) || create == update
}
}


この状態でエラー有り/無しをそれぞれCurlで叩いた結果が以下です。


エラー有り

curl -X POST -H "Content-Type: application/json" -d '{"id":1, "create":"2018-11-03", "update":"2018-11-02"}' localhost:8080/my

[Field error in object 'myModel' on field 'later': rejected value [false]; codes [AssertTrue.myModel.later,AssertTrue.later,AssertTrue.boolean,AssertTrue]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [myModel.later,later]; arguments []; default message [later]]; default message [updateがcreateより過去]]


後書き

記事は7日目へ続きます。


参考にさせていただいた記事