Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom fields with custom validation for reuse between structures. #239

Open
victorcrimea opened this issue Feb 1, 2023 · 8 comments
Open

Comments

@victorcrimea
Copy link

Marshmallow has an option of defining custom field types that can be reused multiple times. This significantly reduces logic errors when you have to reuse the same field over and over again across the whole business logic.

Right now there is a limitation that structs annotated with #validate should have only named fields.

Is it possible to remove that limitation for a case when a structure has only one unnamed field and nothing else. And in this case validate the inner data instead?

Below is the code example that utilizes this feature: both UpdateLocaleRequest and GetLocaleResponse use the same type LocaleName which has a validation defined on the struct and propagated to fields that use this type by having #[validate(customtype)]

#[derive(Debug, Deserialize, Serialize, JsonSchema)]
#[validate(length(equal = 2))]
pub struct LocaleName(pub String);

#[derive(Serialize, Deserialize, JsonSchema, Validate)]
struct UpdateLocaleRequest {
	/// user_id is ignored. need for old api.
	user_id: Option<u64>,
	/// Locale name
	#[validate(customtype)]
	locale: LocaleName,
}

#[derive(Serialize, Deserialize, JsonSchema)]
struct GetLocaleResponse {
	/// Locales' names
	locales: Option<Vec<String>>,
	/// The unique identifier for the user.
	user_id: Option<u64>,
	/// Locale name
        #[validate(customtype)]
	locale: Option<LocaleName>,
}
@Keats
Copy link
Owner

Keats commented Feb 1, 2023

Validation errors take a &str as key to report errors. What would be the key used in the first struct, disregarding the following 2?

@victorcrimea
Copy link
Author

The first struct is not meant to be used directly to validate itself when out of structure. This is just a thin wrapper that allows having validation rules separately from the struct.

If validate() is called directly on LocaleName structure we can either return error saying that validation is impossible or use outer structure name as a key namely "LocaleName".

@victorcrimea
Copy link
Author

@Keats
Do you see anything that may block this proposed behavior? I'm trying to evaluate if there is just a lack of implementation or some existing functionality explicitly blocks this.

@Keats
Copy link
Owner

Keats commented Feb 5, 2023

I'm not sure tbh. The derive is due for a full rewrite so I'm wondering if there's a cleaner way to handle the marshmallow custom Field

@victorcrimea
Copy link
Author

@Keats That is what I have seen in serde. They treat struct CustomType(u64) as u64 during serialization and deserialization. That is why I expected it to be in this way before I found out it's not.

References: serde-rs/serde#1309 and serde-rs/serde#104

@ali-bahjati
Copy link

Maybe just use indices? 0, 1, ...?

@victorcrimea
Copy link
Author

Maybe just use indices? 0, 1, ...?

Can you elaborate? I don't see how indices can be used here?

@ali-bahjati
Copy link

ali-bahjati commented Apr 17, 2023

Sorry that this was confusing.

@victorcrimea I was mostly answering to @Keats first comment:

Validation errors take a &str as key to report errors. What would be the key used in the first struct, disregarding the following 2?

While I think handling a single item wrapped struct is great I think we might be able to just solve it for all unnamed structs like this:

#[derive(Debug, Deserialize, Serialize, Validate)]
pub struct LocaleName(
    #[validate(length(equal = 2))]
    pub String,
    #[validate(...)]
    pub String,
);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants