Eve: Building RESTful APIs with MongoDB and Flask Transcripts
Chapter: Schema definitions and validation
Lecture: Custom rules and types
Login or
purchase this course
to watch this video and the rest of the course contents.
0:00
We already learned that Eve offers a wide and flexible range of validation and transformation rules.
0:07
No matter how powerful and rich a validation system is, there will always come a moment when you need to go beyond that.
0:15
This is the case when you want to validate a value that must conform to standards and conventions, which are specific to a certain application field.
0:26
Eve allows to extend the validation system by creating custom rules, adding in new types or using validating functions.
0:35
In this lecture, we're going to see how we can work with these features to unleash the full power of Eve validation system
0:42
and model it to suit our own specific needs. Now, if you look back at our app.py script
0:50
we realize that we haven't really been working on it for a good while most of our time is being spent on the settings file
0:59
and this is nice because we've been changing how our service responds to requests updating its schema
1:07
endpoint configuration, everything we've done it's been always a declarative thing, we just updated our settings files,
1:15
but now that we want to extend the validation system features set we need to write some code, and this is probably very exciting.
1:23
So let's start by important from eve.io.mongo as you can see, the eve.io.mongo name space
1:39
exposes a validator class, this is the class used by Eve by default. And you see, it is stored within the Mongo name space,
1:49
which already hints at the fact that you can have probably more than one validator maybe a SQL data layer will be using its own validator,
1:59
which makes sense if you think about it. Now that we have a validator class, we want to subclass it.
2:08
Let me save these, as you can see, the server has restarted here, and how do I use my validator to replace the standard one,
2:17
well, this is super easy, all I have to do is pass it to my instance. So this is how I replace the standard validator
2:33
coming in this case with the Mongo data layer with a custom one, right now we aren't really doing anything,
2:41
my validator here is exactly the same as the in-house validator, so to speak. Let's, see how we can improve on it.
2:49
Just for fun, let's assume that we're really interested in only accepting odd numbers for a certain field, and we want to build a custom rule for that.
2:57
We want to be able to go to our settings file, pick our age field here and say, yes, it is an integer, but look, we also want this integer to be odd.
3:14
So we want the rule like this one is odd true, which means age must be an odd integer,
3:24
let's just get rid of this coerce function here just to avoid confusion. Let's, go back and let me paste the code for this validation,
3:35
here it is, so as you can see, the way you create a new rule, is defining a private function, you can tell it is a private one
3:44
because it has this underscore at the beginning, which is a convention in Python for private functions within a class.
3:50
And then you have the validate keyword, and then another underscore and then actuall rule name so validate is odd. Of course it is a class function,
4:01
we're accepting this is odd, which is a boolean, and then the field and value for the field which we have to validate against.
4:11
Implementation is very simple, it is just the test if the number must be actually odd and it isn't, then set an error.
4:19
So here you see how you set an error, you just invoke the error method you pass the field and the description for the error, and that's it.
4:29
So let's save, server restarts, and let's go to Postmen and see what we've done. So here I'm posting last name and age,
4:40
last name I'm adding it because it is required if you remember and age is 18, let's try to post this. And we get an error, unprocessable entity,
4:50
and as you can see, age value must be an odd number. Let's try with 19— good. We now know how we can define custom rules
5:05
and apply them to whatever field we need. But what if we want to the define custom types instead?
5:12
Let's go to our settings file and look at this email field. It is a string and we are applying our regular expressions rule against it,
5:21
it works fine, but if we had more email fields, and maybe in other endpoints in our service, every time we'd need to copy and paste all this stuff here
5:31
which is also prone to errors, it would be much better if we could define a type email this way we would not need to type any regular expressions
5:41
and our type would be reusable anywhere even in different services in our microservices network maybe.
5:51
We can do that, let me save this type definition and go back to our app. The way we define a custom type
5:59
is very similar to how we define a custom rule, _validate type, now the intellisense here is already hinting at how the Mongo validator
6:13
is extending the base validator class as you can see all these types here are Mongo types, So let's define our email as a class method,
6:33
this is how you define a custom type, let me paste the actual code. So if the regular expression is not matched, then set the field error.
6:45
Now, before we say we need to import regular expression module, let me save, relaunch. Now, if we try this post here, email should be a type,
7:06
you see we get value is not a valid email for the email field. Let me try with a valid email. Great, back to our editor,
7:19
So here is our code, as you can see, a simple class, subclassing the Mongo validator, and you can define custom rules or custom types,
7:28
and these are reusable, you can import your specialized class whenever you need to, If you're building multiple services with Eve,
7:38
you can reuse your class in all of these services which is interesting if you're building a micro services network.
7:46
And the way you pass your validator to the Eve instance is simply passing it when you instance the class as an argument.