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

Support custom errors #161

Closed
greyblake opened this issue Jul 17, 2024 · 11 comments · Fixed by #168
Closed

Support custom errors #161

greyblake opened this issue Jul 17, 2024 · 11 comments · Fixed by #168
Labels

Comments

@greyblake
Copy link
Owner

greyblake commented Jul 17, 2024

Context

Some orgs and people are not quite happy with auto-generated error types, e.g. it's not possible to customize them, inject extra details, etc.

Requirement

Provide a way for users to:

  • Define and provide error type they want to use
  • Inject their custom validation function that would return Result<(), CustomError>, where CustomError is a user defined error.

Technically it's possible, but the syntax for this needs to be decided.

Consideration

Having this may clash with "unified error": #75, so requires careful thinking.

@boyswan
Copy link

boyswan commented Jul 17, 2024

I would love to see this - is one of the main reasons I'm unable to use nutype

@greyblake
Copy link
Owner Author

greyblake commented Aug 9, 2024

@AlisCode @gobanos @boyswan What do you guys think of the following syntax?

#[nutype(
    sanitize(trim),
    validate(with = validate_name, error = NameError),
    derive(Debug, AsRef, PartialEq, Deref),
)]
struct Name(String);

where

fn validate_name(name: &str) -> Result<(), NameError> {
    if name.len() < 3 {
        Err(NameError::TooShort)
    } else if name.len() > 20 {
        Err(NameError::TooLong)
    } else {
        Ok(())
    }
}

// This actually probably will need to implement fully std::error::Error
#[derive(Debug)]
enum NameError {
    TooShort,
    TooLong,
}

Do you have any alternative proposal to consider?

@boyswan
Copy link

boyswan commented Aug 9, 2024

Looks great!

@AlisCode
Copy link

AlisCode commented Aug 9, 2024

Looks cool!

Although I have to say this breaks a lot with the current nutype philosophy.

Right now, nutype supports e.g. the following attribute :

validate(not_empty, len_char_max = 20), which produces an error enum with 2 variants (NotEmptyViolated, LenCharMaxViolated)

I think it's a good feat of nutype that you're able to provide a multi-step validation, and this proposal attemps to do exactly the reverse which is that you would provide one custom validation function which would contain all your logic in one place. It would probably mean having a lot of code dedicated to the special case.

What if instead, nutype still produced an enum which contains one variant for each step of the validation ?

For example :

struct TooLongError;
fn max_len(input: &str) -> Result<(), TooLongError> {
    if name.len() > 20 {
        Err(TooLongError)
    } else {
        Ok(())
    }
}

struct TooShortError;
fn min_len(input: &str) -> Result<(), TooShortError> {
    if name.len() < 3 {
        Err(TooShortError)
    } else {
        Ok(())
    }
}

#[nutype(
    sanitize(trim),
    validate(
        with(max_len, variant = TooLong),
        with(min_len, variant = TooShort),
    )
    derive(Debug, AsRef, PartialEq, Deref),
)]
struct Name(String);

Produced code :

enum NameError { 
    TooLong(TooLongError),
    TooShort(TooShortError),
    // And here you can support other potential validation steps ...
}

Also right now nutype supports passing in arguments to validators such as for len_char_max = 20. What if the customized validation function needs to be reused between different newtypes, and you wanted to pass in an argument just like for len_char_max ? How do you see that working ?

@greyblake
Copy link
Owner Author

@AlisCode Thank you for your valuable input!
I had a similar thing to what you suggest in mind, though I see it as an orthogonal to this story (support of custom errors VS custom error variants).
Ideally I'd like to have both in some or other form implement, because they serve different needs.

@DJDuque
Copy link

DJDuque commented Aug 21, 2024

What if instead, nutype still produced an enum which contains one variant for each step of the validation ?

This would "pollute" (even more than it currently does) the public API of libraries that want to use nutype. Maybe a different approach, more centered towards fixing #75, fits better?

@DJDuque
Copy link

DJDuque commented Aug 21, 2024

Maybe good inspiration on how to handle "let users customize errors" can be taken from parser combinator libraries? Feels like nutype validation errors can take inspiration on how they handle parsing errors (?) I don't know, just throwing ideas out there.

Maybe there is something to copy from the work that @epage has done in winnow? Again, I don't know, just throwing random ideas around.

@greyblake
Copy link
Owner Author

@DJDuque Could you explain how winnow error idea would fit here?

@greyblake
Copy link
Owner Author

greyblake commented Aug 24, 2024

@boyswan @AlisCode @DJDuque
I just released 0.5.0-beta.2, with the support of custom validation and errors.

I'd appreciate if you find a bit of time to try it out and give me feedback before I release 0.5.0 (planning in ~1 week).

See the docs in the Custom validation with a custom error type section.

@memark
Copy link
Contributor

memark commented Aug 24, 2024

I don't recall being involved in this issue, maybe you meant to tag someone else, @greyblake?

@greyblake
Copy link
Owner Author

@memark Sorry my bad.

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

Successfully merging a pull request may close this issue.

5 participants