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