Webアプリケーションサーバのフレームワークなどでは、受け付けたリクエストのデータが適切かをチェックするためのバリデーション機能があります。
Rustでは汎用的なバリデーションのクレートとして validator が存在しており、こちらを使う機会があったので今回はその紹介をします。
Validatorを導入する
Validatorの導入ですが、通常の Cargo.toml
に以下を追加することで可能です。
[dependencies] validator = { version = "0.14", features = ["derive"] }
READMEによると、導入には、Rust 1.42 以上が必須となっていますので、その点だけご注意ください。
validate を使えるようにする
struct
に対して、 #[derive(Validate)]
をつけることで、バリデーションの関数 validate
が使えるようになります。
#[derive(Validate)] struct User { pub name: String } User{ name: "Bob" }.validate();
validate
は Result<(), ValidationErrors>
を返す関数です。バリデーションがすべて成功すれば、 Ok(())
、 そうでなければ Err<ValidationErrors>
が返ってきます。
現在は特に条件などがないため、 Ok(())
が返ってきます。
validatorを指定する
デフォルトで基本的なバリデーションの機能は用意されています。
validator | 検証する内容 | 主な対象の型 | 引数 |
---|---|---|---|
妥当なメールアドレス | String | ||
url | 妥当なURL | String | |
length | 長さ | String, Vec | min, max, equal(1つ以上必須) |
range | 数値の範囲 | i32, u32, f32 | min, max(1つ以上必須) |
must_match | 2つのフィールドの一致 | i32, String, Vec | other |
contains | 文字列もしくはhashmapのキーに含まれる | String, HashMap | pattern |
regex | 正規表現に一致 | String | path |
credit_card | 妥当なクレジットカード番号 | String | |
phone | 妥当な電話番号 | String | |
custom | カスタムバリデータを実行 | function, arg | |
non_control_character | 制御文字を含まない | String | |
required | Someである | Option |
|
required_nested | Someかつ含むインスタンスのバリデーションも成功する | Option |
実際に利用する際は以下のようにします。1つのフィールドに対して複数のバリデーションを指定できます。
#[derive(Validate)] struct User { #[validate(required)] #[validate(length(min = 1, max = 24))] name: Option<String> }
READMEにかなりわかりやすく書いてあるので、そこまで詰まることはないかと思います。
https://github.com/Keats/validator#validators
また、上記にくわえ、Validate を継承した型を利用しているフィールドで、その型のバリデーションも実行したい場合は以下のようにします。
#[validate]
attributes: Attributes
また、READMEだけだと少しわかりにくいものとして、 must_match
があるかと思います。イメージとしては、パスワードと確認用の入力が一致しているかのような2つのフィールドの一致を検証したい際に利用します。
#[validate(must_match = "password")] password: String, #[validate(must_match(other = "password"))] password_confirmation: String
また、デフォルトのエラーコードやメッセージを上書きすることができます。
#[validate(email(code = "error code"))] foo: String, #[validate(length(min = 1, max = 2, message = "message"))] bar: String
カスタムバリデーション
クレートに用意されていないバリデーションは、 custom
で実行することができます。
fn validate_exact_foo(value: &str) -> Result<(), ValidationError> { if value == "foo" { Ok(()) } else { Err(ValidationError{ code: Cow::from("exact_foo"), message: Some(Cow::from("Do not exact `foo`.")), params: Default::default() }) } } #[derive(Validate)] struct User { #[validate(function = "validate_exact_foo")] user: String }
まとめ
validator
は割と素直に使えるバリデーションのクレートで、必要十分な機能を備えているかと思います。
ただし、カスタムバリデータでは、 ValidationError
を返す必要があるため複数のエラーを返すことができません。そのため、まとめるよりも極力分離して指定していく必要があります。
また定義時のバリデーション指定で、組み込みのバリデータのように引数を指定できるような形式で作ることができないのが少し残念なところではあります。
とはいえ、多少工夫すればそのあたりも問題になりにくいため、今後もRustでバリデーションが必要な場合は使っていきたいと思います。