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
User-friendly error messages for type validation #21
Comments
Actually it's not only the complex types really. You will likely have the same problem if you try |
Indeed, type validation occurs before passing the value to the validator(s). The rationale behind this that user validators are expected to receive a value of type re: The Thanks for reporting! |
The motivation of this kind of validation is clear but that breaks the whole idea of user-friendly error messages. The simplest example - the user providing a string where an integer is required - already "breaks" the error handling. try:
ret = self.type(ret)
except:
msg = 'Expected type {}, got {}'.format(JSON_TYPES[self.type.__name__],
JSON_TYPES[type(ret).__name__])
raise ValidationError(self.error or msg) with a basic map of JSON types: JSON_TYPES = dict(
int='Integer',
str='String',
dict='Object',
list='List'
) |
Yes, I think the current error messages for type validation can definitely use improvement. I think you have the start of a good solution. I would suggest using the terminology used in JSON Schema for the primitive types. Also, a default error message should be used if the value is not in the If you would like to send a pull request, I would gladly review and merge it! |
Thanks! I'll work on a pull request. |
@Ch00k Thank you for offering to work on this. I have updated the title of the issue to more accurately reflect the problem being solved. |
@sloria Sure. It looks like the idea of having proper type validation is a lot more difficult to implement than I initially thought. Specifically because of the need to support different targets and also different Python versions. I already started experimenting and created a PR #24. It's still very far from ready, lots of existing tests fail but still please take a look if you have any feedback on this. |
I'm coming here from flask-restful / reqparse. I like how it doesn't differentiate between type coercion and validation. For example, I can do this: def to_bool(value, name):
if isinstance(value, bool):
return value
if isinstance(value, basestring):
if value.lower() in ['true','yes','on']:
return True
if value.lower() in ['false','no','off']:
return False
raise ValueError("The parameter '{}' should be true/yes/on or false/no/off, but it was {}".format(name, value))
from flask.ext.restful import reqparse
parser = reqparse.RequestParser()
parser.add_argument('cool', type=to_bool, required=True) In most situations it'd probably be easiest to just write a little function like this that handles both type coercion and validation all at once. |
Giving validators a single point of responsibility is beneficial for maintainability and reuseability. It also makes validators easier to write because they only have to worry about one type of input. If you really want to do both type coercion and validation in the same function, you can still pass the from webargs import Arg, ValidationError
def to_bool(value):
if isinstance(value, bool):
return value
if isinstance(value, basestring):
if value.lower() in ['true','yes','on']:
return True
if value.lower() in ['false','no','off']:
return False
raise ValidationError("The parameter '{}' should be true/yes/on or false/no/off, but it was {}".format(name, value))
args = {
'cool': Arg(use=to_bool, required=True)
} |
Closed by #24. |
Let's say I have a PUT method that must be given a JSON of this structure:
My code then would look like this:
The problem I have is with webargs' type coversion, namely this part of code. So if I provide this kind of JSON:
{ "imdb_data": 1 }
, my custom validation functionvalidate_imdb_data_json
will not even get a chance to work because validation will fail before it gets called, on line 172. And I will result in a response like this:which is actually the result of an attempt to do
dict(1)
(btw this is again weird because the code catchesValueError
but this kind of error is aTypeError
, but this is a different conversation).The only way I can think of to work around this is to not pass
type_
at all. Then all the validation will be done byvalidate_imdb_data_json
function. But that does not look right to me. Is there something I am missing?This is somewhat similar to #18.
The text was updated successfully, but these errors were encountered: