Rust validatorを導入する

個人開発したアプリの宣伝
目的地が設定できる手帳のような使い心地のTODOアプリを公開しています。
Todo with Location

Todo with Location

  • Yoshiko Ichikawa
  • Productivity
  • Free

スポンサードリンク

actix-webにvalidation処理を導入したので記録しておきます。

使用したcrateはこちら。

GitHub - Keats/validator: Simple validation for Rust structs


Cargo.toml

validator = { version = "0.12", features = ["derive"] }

deriveを指定することでstructのtraitして利用できるっぽい。


validationの記述

構造体にマクロとして定義できる。actix-webから渡されるリクエスト構造体に対して、derive(Validate)を指定。

use validator::{Validate, ValidationErrors, ValidationError};

#[derive(Debug, Validate, Deserialize)]
pub struct RequestBody {
    #[validate(email)]
    email: String,
    #[validate(length(min = 4))]
    password: String,
}

指定できるリテラルは上記のreadmeを見るのが早い。


validationの実行

Handler側でデシリアライズされたデータに対して、validate()メソッドでvalidationを実行。

バリデーションがinvalidだとErrが返される。

match request_body.validate() {
    Ok(_) => (),
    Err(error) => return Ok(HttpResponse::BadRequest().json(ResponseValidationError {
        error
    }))
}

上記で束縛しているErr(error)ValidationErrors型なので、この型をシリアライズすればJSONでレスポンスを返せる。


ValidationErrorsのシリアライズ

#[derive(Serialize)]
pub struct ResponseValidationError {
    error:ValidationErrors
}


アプリケーションエラーもValidationErrors型に合わす

例えば、signup時のemail重複のチェックなど、ライブラリ外のチェックエラーもレスポンスフォーマットを合わしたほうがフロント側で都合がいいときがある。

ValidationErrorsを生成して返すのが楽。

if let Err(_) = mail_result {
    let mut error = ValidationErrors::new();
    error.add("email", ValidationError{
        code: Cow::from("email is already exists"),
        message: None,
        params: HashMap::new()
    });
    return Ok(HttpResponse::BadRequest().json(ResponseValidationError {
        error
    }))
}

codeにメッセージを入れたんだけど、これはまあフロント側で解釈しやすい方にセットしてあげればいいと思う。