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 #100

Closed
amcdnl opened this issue Jan 20, 2016 · 32 comments
Closed

Custom Error Messages #100

amcdnl opened this issue Jan 20, 2016 · 32 comments
Labels

Comments

@amcdnl
Copy link

amcdnl commented Jan 20, 2016

The docs are a bit terse so I'm not entirely sure on this, but do you have the ability to define custom error messages?

@epoberezkin
Copy link
Member

epoberezkin commented Jan 20, 2016

Not in ajv at the moment. You can create your own messages based on error.params. How would you envisage defining them I wonder?

My idea was this: https://github.com/json-schema/json-schema/wiki/Custom-error-messages-(v5-proposal), but I am not sure yet what the templating approach should be. I'd like to have something like relative-json-pointer-expression, to be honest, that would include interpolated strings.

@amcdnl
Copy link
Author

amcdnl commented Jan 20, 2016

I'm not entirely in love with this API, but this is kinda what I was thinking: https://github.com/bugventure/jsen#custom-errors

@epoberezkin
Copy link
Member

yeah, I saw it. It won't be exactly that, for sure.

@Xamage
Copy link

Xamage commented Mar 4, 2016

👍
This feature would be very interesting to me, too bad it isn't handled in ajv... As amcdnl said, a format like (jsen) would be cool :

var schema = {
    type: 'number',
    minimum: 18,
    messages: {
        type: 'Must be a number',
        minimum: 'No children...'
    }
}

also with the hability to provide a function :

messages: {
     length: function(val, obj) {
           return obj.otherProperty === true ? "You're wrong" : "You're not right";
     }
}

@joaoreynolds
Copy link

+1

@epoberezkin
Copy link
Member

I am thinking about implementing invalidMessage and requiredMessage as custom keywords and add them to ajv-keywords. This way those who need this functionality can use those keywords without polluting the namespace and increasing the size of ajv for everybody else.

These keywords will analyse errors collected so far for the same property/item and if it was invalid/required the error will be added. Then it's possible to filter those errors out (using keyword property of the error object).

What do you think?

@claudio-viola
Copy link

hi @epoberezkin . Just to add my voice.
I believe this is a much needed feature.
If I understood right your approach. If you get a validation error and if there is an invalidMessage / requiredMessage defined for that property it will be added into the error object
Is that so?

@claudio-viola
Copy link

Isn't this already achievable using verbose:true and accessing parentSchema.invalidMessage?
What will the keyword add that cannot be done already?

@epoberezkin
Copy link
Member

The keyword schema is indeed accessible, but depending on the format of this schema the keyword can do more - e.g., it can have different errors for different rules or maybe it can merge and remove collected errors into one error.

But you are right, on a simple level all that's needed is to add some info in the schema using any keyword and to access it via error object to create the list of application specific errors.

@crkepler
Copy link

crkepler commented Jul 3, 2016

+1.

I'm writing an API that will use ajv (hopefully) and I need to have exact control over the messages for translation purposes.

Ideally I'd provide a default error message for each property, sometimes not caring about what exactly caused the error (e.g. type or required).

I'm currently using revalidator, which allows custom messages, but I'm looking forward to switching to ajv. Indeed, a much needed feature!

@epoberezkin
Copy link
Member

@crkepler The suggestion above by @claudio-viola can be helpful. In any case this functionality will be implemented as an [optional] custom keyword. What is the syntax for custom errors used in revalidator? I don't see it in the repo.

Also revalidator doesn't seem to be particularly close to the standard (looking at the docs and at the benchmark).

@crkepler
Copy link

crkepler commented Jul 4, 2016

@epoberezkin: first, thanks so much for your amazing work done here. I agree, revalidator isn't standard and that's why I'm recommending our team to leave it and use ajv. Here's an example of how we implement custom messages in revalidator (FYI only, I don't necessarily suggest this approach, although it works for us):

{
    "type": "object",
    "properties": {
        "organizationId": {
            "type": ["string", "null"],
            "required": false,
            "allowEmpty": false,
            "minLength": 1,
            "maxLength": 80,
            "message": "When supplied, 'organizationId' must be a string between 1 and 80 characters long."
        },
        "name": {
            "type": "string",
            "required": true,
            "allowEmpty": false,
            "minLength": 1,
            "maxLength": 250,
            "message": "The organization 'name' can't be empty and it must be a string between 1 and 250 characters long."
        },

Thanks for much for considering this feature, it'd be a tremendous help for us. Keep up the great work!

@epoberezkin
Copy link
Member

epoberezkin commented Jul 4, 2016

Thank you. I can also see in revalidator test that it supports messages keyword to define keyword-specific messages.

So I am considering implementing custom keyword errorMessages that can be a string or an object.

If it's a string "error_message" and the validation fails on the current level it will add an error object:

{
  keyword: 'errorMessages',
  message: 'error_message',
  params: { keywords: ['...' /*, '...', ... */] } // failing keywords
  // other properties as usual
}

If it's an object, then it's keys are keywords and the values are strings with errors for each keyword (a bonus would be to allow templates referring to the keyword schema and data values). required and dependencies keywords are special, they should also allow property specific messages (as there is no such thing as "required": true in draft 4 and instead the array of properties should be used on the object level).

{
  "properties": {
    "size": {
      "type": "number",
      "minimum": 4,
      "multipleOf": 2,
      "errorMessages": {
        "type": "size should be a number",
        "minimum": "size should be bigger or equal to 4",
        "multipleOf": "size should be even"
      }
    }
  },
  "required": ["size"],
  "errorMessages": {
    "required": {
      "size": "size is mandatory"
    }
  }
}

In this case instead of adding additional error objects, the keyword would add the property errorMessage to them (it's better than replacing message property as it would still allow functions such as errorsText produce meaningful results and also i18n would not replace errors in those additional properties.

Or maybe it's better to always add additional objects - they can be easily filtered out. Need to think about it.

This custom keyword will be defined in ajv-keywords package so it would be quite easy to use.

Suggestions? @amcdnl @Xamage @joaoreynolds @claudio-viola @crkepler

@epoberezkin
Copy link
Member

Or maybe even in a separate package ajv-errors, ajv-keywords would stay for custom validation keywords then...

@crkepler
Copy link

crkepler commented Jul 4, 2016

@epoberezkin all the approaches you're suggesting are flexible and easy to implement for us users. So, I have no preference for the implementation you choose. However, using a separate package seems to be less risky for development (and easier to test?), and also more extensible and decoupled from the existing code.

@deragon
Copy link

deragon commented Nov 3, 2016

Newbie to Ajv and JavaScript here... For me, it is not clear what this issue is about. Is it about adding custom keywords and having custom error messages associated to them? Or is it about adding custom error messages to existing, Ajv provided keywords?

@epoberezkin
Copy link
Member

About the latter, custom error messages for different validation failures, not necessarily based on a single keyword. Custom keywords are already supported.

@crkepler
Copy link

crkepler commented Nov 29, 2016

PLEDGE: Contribute any amount to this project and I will match your contribution 100%, to reach the project goal of US$ 500.00.

There's still US$ 425.00 to go, so my needed match limit is US$ 212.50, which I'll happily contribute as others chip in. I prefer not to be the sole contributor and would like more people involved.

My pledge is valid until 4-July-2017, one year after the first contribution was made.

Please, contribute any amount you can:

https://www.bountysource.com/issues/30029477-custom-error-messages

@crackcomm
Copy link

@epoberezkin is there a final standard that should be implemented?

@danielantelo
Copy link

hey guys, what is the right way to do this then? cannot find concrete examples in the doc. I just want to be able to change the default error messages for custom ones. thanks!

@epoberezkin
Copy link
Member

@danielanteloagra to change the error messages you need to process them in your code after validation, there is no other way at the moment. You can look in the code that ajv-i18n package uses for this purpose and follow the same pattern (ajv-i18n doesn't allow defining your own messages at the run time, but it can help understand how to do change the validation messages).

@danielantelo
Copy link

thanks @epoberezkin
That's a shame, as we are trying to share the schema between systems... not nice that each system then has to do work to override the validation messages :( is there a plan to integrate it into the actual json in the future?

@epoberezkin
Copy link
Member

epoberezkin commented Mar 3, 2017

This issue is a plan :)

@epoberezkin
Copy link
Member

@crkepler
Copy link

crkepler commented Mar 6, 2017

@epoberezkin: It looks awesome, exactly as I'd expect!

I only have one suggestion, if that's OK. What do you think about adding a "catch all" message, for cases in which we don't want to specify an individual message for every single constraint? Using your example, see the "message" property I added below as an example:

 "properties": {
    "size": {
      "type": "number",
      "minimum": 4,
      "multipleOf": 2,
      "errorMessage": {
        "type": "size should be a number",
        "minimum": "size should be bigger or equal to 4",
        "multipleOf": "size should be even"
        "message": "size should be an even number, greater or equal than 4"
      }
    }

"message" in this case, is a "catch all" error message, with the lowest priority of them all. If there's a an errorMessage property for the violation, use it. If not, use "message". If there's no "message" defined, nothing is returned. Does this make sense? What do you think?

Thanks again for your thorough analysis on this issue. It's really exciting stuff!

@epoberezkin
Copy link
Member

@crkepler There are two scenarios possible here: 1) no messages that are defined match but there are some other errors. 2) some messages match and there are some other errors as well.

The example above makes sense in scenario 1, but not much sense in scenario 2. Potentially we could have two catch-all messages:

  1. defaultMessage (like in your example, for scenario 1
  2. otherErrorsMessage (for scenario 2, it could be "size is invalid")

Not sure I like it to be honest - it's getting complicated :)

A simpler options would be to have only one defaultMessage and use it:

  1. only in scenario 1
  2. only in scenario 2
  3. in both cases

What do you think?

@epoberezkin
Copy link
Member

Also as we are defining catch all messages (and even without this extension we need them in case string rather than object with keyword-specific messages is used) than we probably need to be able to some elements from errors (e.g. the list of keywords) in the string templates...

@epoberezkin
Copy link
Member

@crkepler also I think error classification could be a part of this feature, it was asked a couple of times.

@crkepler
Copy link

@epoberezkin - What a privilege it was talking to you on Skype; a great pleasure to meet you. You're a first class person, not to mention one of the smartest developers I've ever met.

The bounty goal has been achieved and it was an honor for me to contribute to this project. I hope you get to implement this complex feature -- it looks so simple at first, but it is not.

@epoberezkin
Copy link
Member

@crkepler thank you for the support. I will do it.

@epoberezkin epoberezkin added this to the 6.0.0 milestone Mar 22, 2017
@epoberezkin epoberezkin removed this from the 6.0.0 milestone Apr 30, 2017
@epoberezkin
Copy link
Member

Some limited functionality is available in ajv-errors, more to follow.

@epoberezkin
Copy link
Member

1.0.0 published

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

No branches or pull requests

9 participants