nutype icon indicating copy to clipboard operation
nutype copied to clipboard

Support `serde` attributes

Open TheBestTvarynka opened this issue 1 year ago β€’ 5 comments

Hi, I like your library a lot and I use it regularly.

Today I tried to use serde attributes on my new-type struct but failed. Here is an example:

#[nutype(
    validate(predicate = |token| !token.is_empty()),
    derive(Debug, Serialize, Deserialize, AsRef, Deref, TryFrom),
)]
#[serde(serialize_with = "...", deserialize_with = "...")]
pub struct InvitationToken(Vec<u8>);

The compiler says error: #[nutype] does not support this attribute.. I also tried this one:

#[nutype(
    validate(predicate = |token| !token.is_empty()),
    derive(Debug, Serialize, Deserialize, AsRef, Deref, TryFrom),
)]
pub struct InvitationToken(#[serde(serialize_with = "...", deserialize_with = "...")] Vec<u8>);

As I understand, this is unsupported yet. Am I right?

TheBestTvarynka avatar Jan 05 '25 19:01 TheBestTvarynka

@TheBestTvarynka Thanks for the report!

Yeah, at the moment nutype generates it's own Deserialize implementation with respect to the sanitization & validaiton, not paying any attention to serde attributes.

Does your implementation of deserialize_with return Vec<u8> ?

greyblake avatar Jan 07 '25 08:01 greyblake

Does your implementation of deserialize_with return Vec<u8> ?

yes

This is my use case:

// https://github.com/TheBestTvarynka/Dataans/blob/582dd48b5e8f05f859d1b8d21db1b97f0c56cab7/crates/web-api-types/src/lib.rs#L14-L18
#[nutype(
    validate(predicate = |token| !token.is_empty()),
    derive(Debug, Serialize, Deserialize, AsRef, Deref, TryFrom),
)]
pub struct InvitationToken(Vec<u8>);

// https://github.com/TheBestTvarynka/Dataans/blob/582dd48b5e8f05f859d1b8d21db1b97f0c56cab7/crates/web-api-types/src/auth.rs#L10-L14
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SignUpRequest {
    pub invitation_token: InvitationToken,
    pub username: Username,
    pub password: Password,
}

This invitation token is a bunch of bytes, but I want these bytes to be base64 or hex-encoded in the resulting json.

I found a workaround: I can set the deserialize_with attribute on the invitation_token field of the SignUpRequest struct. However, this forces me to do this every time I use the InvitationToken struct.

TheBestTvarynka avatar Jan 07 '25 08:01 TheBestTvarynka

Would you mind sharing your implementations of deserialize_with and serialize_with?

Unfortunately I cannot promise a fix for this quickly.

For now I'd suggest you to go maybe with your own manually implemented type.

greyblake avatar Jan 07 '25 08:01 greyblake

Would you mind sharing your implementations of deserialize_with and serialize_with?

Something like this: github/TheBestTvarynka/crypto-helper/69dd4cd/src/serde.rs#L8-L37. I planned to copy-paste this code into my current project πŸ˜…

TheBestTvarynka avatar Jan 07 '25 08:01 TheBestTvarynka

I have the same wish. Posting my use case s.t. you have something to work against when you find the time:

#[nutype(validate(predicate = |u| u.scheme().is_some_and(|u| u == "https")), derive(Serialize, Deserialize))]
pub struct HttpsUri(Uri);

Then I'd like to use #[serde(with = "http_serde::uri")] :)

atezet avatar Feb 19 '25 13:02 atezet