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 error messages #33

Closed
RyanMcDonald opened this issue Apr 16, 2020 · 15 comments
Closed

Custom error messages #33

RyanMcDonald opened this issue Apr 16, 2020 · 15 comments
Labels
enhancement New feature or request

Comments

@RyanMcDonald
Copy link

Is there a way to hook into the validation error messages to provide custom ones?

This would be useful for client-side validation when the errors are user-facing and might need to be translated.

@colinhacks colinhacks added the enhancement New feature or request label Apr 17, 2020
@colinhacks
Copy link
Owner

colinhacks commented Apr 17, 2020

@RyanMcDonald I'm open to implementing this. Do you have a proposed API?

@RyanMcDonald
Copy link
Author

@vriad I was envisioning something like Yup's locale dictionary or their typeError method.

@pierreis
Copy link
Contributor

I think the typeError is good 👍
It could be combined with #37, to add a method typeError(ErrorMsg<Type>) to ZodType.

@RyanMcDonald
Copy link
Author

Another, possibly easier solution would be to expand on the ZodError class to include something like a validation key that we can use to determine what message to show.

@colinhacks
Copy link
Owner

That is probably the solution I'd go with. You can already get the path of the error, which can tell you, say, which property of the object didn't pass validation. What other information would you be looking for in this "validation key"?

@colinhacks
Copy link
Owner

Also @RyanMcDonald I just implemented custom validations which do support custom error messages.

@RyanMcDonald
Copy link
Author

What other information would you be looking for in this "validation key"?

We would need to know what type of validation failed. For example, given this error object:

{
  "path": [ "name", "last" ],
  "message": "Non-string type: number"
},

We wouldn't be able to translate that because we're only given a message. We don't know which rule failed. However, if it were something like this:

{
  "path": [ "name", "last" ],
  "message": "Non-string type: number",
  "type": "non-string"
},

Then we could index that in our translations file:

"validation_errors.type.non-string": "Non-string type: {givenType}"
try {
  person.parse({
    name: { first: 'Dave', last: 42 },
    age: 'threeve',
    address: ['123 Maple Street', {}],
  });
} catch (err) {
  const errorMessages = err.errors.map(error =>
    translate(`validation_errors.type.${error.type}`, { givenType: typeof _.get(error.path, person) }
  );
  console.log(errorMessages);
}

@blackrabbit99
Copy link

That is probably the solution I'd go with. You can already get the path of the error, which can tell you, say, which property of the object didn't pass validation. What other information would you be looking for in this "validation key"?

@vriad what about to allow override custom error for example in a way joi does https://hapi.dev/module/joi/api/?v=17.1.1#anyerrorerr

Custom validator is absolutely great feature but there is still not a way to communicate error to the customer:

  • Errors could not be handled path is necessary part of error but hardcoded messages are hardly could be processed :(
  • There is no straight forward way to internationalise errors
  • It would be pretty straightforward to allow to assign custom payload to errors so consumers will be able to solve their use cases in the most flexible manner
  • Customers should have an ability to customize error not only on refine level

Late night proposal :)

export abstract class ZodType<Type, Def extends ZodTypeDef = ZodTypeDef> {
public error(errorPayload: object|string) {
    this._def.customErrorPayload  = errorPayload;
    return this;
}
}

So customer will be able to run something like:

const userSchema = z.object({
        firstname: z.string().error({message: 'You are not able to leave firstname empty'}),
        lastname: z.string().refine(val => val.startsWith('Z'))..error({message: 'Lastname should start with Z letter', type: 'IncorrectFirstLetter', detail: {firstLetter: 'Z'}})
});

and as the result error will contain assigned attributes so consumer will be able to customize his UI in any manner.

@blackrabbit99
Copy link

WIP proposal
c98d7d8

@colinhacks
Copy link
Owner

Hi Artem,

I've spent quite a bit of time looking into your solution and the approaches of many other libraries.

I really appreciate the effort you put into this, but I don't think it's the best approach. The appeal of the chainable/fluent interface is that you can compose a bunch of validation checks easily. For example:

z.number().refine(x => x > 5).refine(x => x < 12)

Zod's approach to error handling must make it easy to know which of these validations is failing. That's why I endorsed the "validation key" approach ("error code" is probably a better term) described by @RyanMcDonald.

Your solution (while admirably flexible) quashes that granularity; any schema with a customError set in its def can only return a single error. This is true also for schemas with multiple chained calls to .refine, like my example above.

Unfortunately I didn't have time this weekend to implement this, but hopefully I will sometime this week. I want to rewrite Zod such that it never deals with error messages, only error codes (e.g. not_a_number, nonempty_array_is_empty, etc). Converting those codes into error messages can be done by the consumer externally from Zod.

@Kurnett
Copy link

Kurnett commented Jul 8, 2020

Are there any updates on the status of this issue? I'm loving the library so far, but I'm at a bit of a sticking point with customer-facing error messages and this seems like a fix that's already in the works.

@colinhacks
Copy link
Owner

@Kurnett I'll publish a beta version in the next couple hours. I've been holding off until the testing and documentation are more complete but you should be able to start using it.

@Kurnett
Copy link

Kurnett commented Jul 8, 2020

Wow, that was fast. Thanks! Looking forward to trying it out.

@colinhacks
Copy link
Owner

colinhacks commented Jul 8, 2020

Just published the full overhaul of the error handling system in [email protected].

Everyone who's been needing this, play around with it and let me know if you have any feedback or ideas 👍

@RyanMcDonald @ozimos @blackrabbit99 @antonku @pierreis @chrbala @brabeji @tuchk4 @mlznlv @HVOROSTYAN @bo-ora @paul-sachs @richdouglasevans @danbergelt @ervasive @xjrk58

@colinhacks
Copy link
Owner

This is now in master and published in [email protected] so I'm gonna close.

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

No branches or pull requests

5 participants