Expand description
§Preprocess
A crate to help you preprocess your structs and enums. Can be used to validate data, or to transform it.
There are two kinds of preprocessors:
- Validators: They check if the given field is valid and don’t modify the value. For example: a validator could check if a string is a valid email address.
- Preprocessors: These allow you to modify the value (and possibly type) of a field. For example: a preprocessor could trim a string, or convert it to uppercase.
§Example usage
use preprocess::prelude::*;
#[preprocess::sync]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct UserSignUpRequest {
// First trims the email, then converts it to lowercase, then validates it as an email address.
#[preprocess(trim, lowercase, email)]
pub email: String,
// First trims the password, then checks if it's at least 8 characters long.
#[preprocess(trim, length(min = 8))]
pub password: String,
}
let processed_value = raw_value.preprocess()?;
§Inheriting derive attributes
Since the crate uses an attribute macro, it must always be the first
attribute on the struct or enum. A new struct / enum will be generated with
the name {original_name}Processed
. The derive macro will inherit all the
derive attributes from the original struct / enum. For example:
use preprocess::prelude::*;
#[preprocess::sync]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UserSignUpRequest {
#[preprocess(trim, lowercase, email)]
#[serde(default)]
pub email: String,
#[serde(alias = "pass")]
#[preprocess(trim, length(min = 8))]
pub password: String,
}
The above code will generate:
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct UserSignUpRequestProcessed {
#[serde(default)]
pub email: String,
#[serde(alias = "pass")]
pub password: String,
}
This way, any custom derive attributes you use (like Serde) will be inherited by the generated struct / enum. This also ensures that you can preprocess your struct / enum and send the preprocessed version to the client, without having to write any extra code.
§List of allowed preprocessors
Preprocessor | Description |
---|---|
email | Validates a string to be a valid email address. |
domain | Validates a string to be a valid domain name. |
ip | Validates a string to be a valid IP Address. |
url | Validates a string to be a valid URL. |
length | Validates the length of a string. |
range | Validates the range of a number. |
contains | Validates if a string contains a substring. |
does_not_contain | Validates if a string does not contain a substring. |
regex | Validates a string using a regex. |
type | Enforces the type of a value using TryFrom . |
trim | Trims a string. |
lowercase | Converts a string to lowercase. |
uppercase | Converts a string to uppercase. |
custom | Validates a string using a custom function. |
More details about each preprocessor can be found in the respective module documentation of preprocessors and validators.
§Custom preprocessors
You can use a custom function as a preprocessor. The function must have the following signature:
fn custom_preprocessor<T>(value: T) -> Result<T, Error>;
The function must return a Result
with the same type as the input. If the
function returns an Err
, the error will be returned as the error of the
preprocessor. If the function returns an Ok
, the value will be returned as
the output of the preprocessor.
pub fn custom_preprocessor(value: String) -> Result<String, Error> {
if value.len() < 8 {
return Err(Error::new(
"Password must be at least 8 characters long",
));
}
Ok(value)
}
#[preprocess::sync]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct UserSignUpRequest {
#[preprocess(custom = "custom_preprocessor")]
pub password: String,
}
§Enforcing the type of a value
You can use the type
preprocessor to enforce the type of a value. This is
useful when you want to convert a value to a different type. For example,
you might want to convert a string to an integer. You can use the type
preprocessor to do this. The type
preprocessor uses TryFrom
to convert
the value to the desired type. If the conversion fails, the preprocessor
will return an error.
#[preprocess::sync]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct UserSignUpRequest {
#[preprocess(type = "i32")]
pub age: i16,
}
§Usage
Add this to your Cargo.toml
:
[dependencies]
preprocess = "<version>"
Then, you can import the crate and use it like this:
use preprocess::prelude::*;
#[preprocess::sync]
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct UserSignUpRequest {
// First trims the email, then converts it to lowercase, then validates it as an email address.
#[preprocess(trim, lowercase, email)]
pub email: String,
// First trims the password, then checks if it's at least 8 characters long.
#[preprocess(trim, length(min = 8))]
pub password: String,
}
§MSRV
There is no MSRV as such, and to be honest, I don’t see the point of an MSRV, with how easy rust is to upgrade. I just use the latest version of rust on my machine. That being said, I don’t think I’ve used any new rust features. So it should work on older versions of rust as well. Please open an issue if you’re facing any, well, issues.
Re-exports§
pub use crate::utils::Error;
Modules§
- prelude
- Prelude module for the library. This module re-exports all the important types and traits from the library. This module is useful when you want to use the library without importing the individual modules.
- preprocessors
- List of all the preprocessors that mutates the given field, including
changing the type if required.
A list of all the preprocessors that preprocess the given field, mutating it
if required. The type of the field may be changed. For example, the
lowercase
preprocessor will change the type of the field toString
. - types
- A list of all the types that are re-exported from supporting crates. Used by the preprocessor to set the types for a field if required.
- utils
- Utility module for the library.
- validators
- List of all the validators that validates the given field without mutating
it. The type of the field may still be changed. For example, the
ip
validator will change the type of the field toIpAddr
. A list of all the validators that only validates the given field without mutating it. The type of the field may still be changed. For example, theip
validator will change the type of the field toIpAddr
.
Traits§
- Preprocessable
- A trait that can be implemented by any type to allow it to be preprocessed.
This trait is automatically implemented for all types that use the
#[preprocess::sync]
macro.
Attribute Macros§
- sync
- An attribute macro for preprocessing structs