Keats / validator

Simple validation for Rust structs
MIT License
1.97k stars 141 forks source link

Enable custom messages in complex custom validator #279

Closed decryphe closed 9 months ago

decryphe commented 10 months ago

This is probably pretty minor, but quite useful for the kind of items we do validation on. There's structs with quite a lot of fields that are interdependent (e.g. if the field enabled is true, the fields tls_cert and tls_key must be set).

To communicate problems with these fields, we can't rely on the default ValidationErrors.to_string() impl without setting a custom ValidationError::message. The reason is that the derive macro will always generate code that calls add_param() with the value being validated - which can contain secrets such as prior TLS keys that should not be leaked.

The current API is a bit cumbersome as it allows only one message per custom validation function. This PR suggests a method on ValidationErrors that can be used to set the message field directly from within the custom validation function where the ValidationError is instanciated.

Example usage after change:

fn validate_my_config(
    config: &MyConfig,
) -> std::result::Result<(), validator::ValidationError> {
    if config.enabled && config.tls_cert == "" {
        return Err(validator::ValidationError::new("config incomplete")
            .with_message(
            "The TLS Cert must be set when the Service is enabled.",
        ));
    }
    if config.enabled && config.tls_key == S::TlsKey::default() {
        return Err(validator::ValidationError::new("config incomplete")
            .with_message(
            "The TLS Key must be set when the Service is enabled.",
        ));
    }
    Ok(())
}