We at Open Event Server project are using flask-restplus for API. Apart from auto-generating of Swagger specification, another great plus point of restplus is how easily we can set input and output models and the same is automatically shown in Swagger UI. We can also auto-validate the input in POST/PUT requests to make sure that we get what we want.
As can be seen above, the
validate param for
namespace.expect decorator allows us to auto-validate the input payloads.
This used to work well until one day I realized there were a few problems.
- When a field was defined as say for example
field.Integer, then it will accept only Integer values, not even
- If there is a string field and it has
requiredparam set to True, then also it is possible to set empty string as its value and the in-built validator won’t catch it.
- Even if I somehow managed to hack my way to support
nullin field, it will also support null even if required=True.
- We had no control on what error message was returned.
Specially problem #1 was a huge one as it questioned the whole foundation of the API.
So we realized it will be better if we don’t use
namespace.expect and use a custom validator.
For custom validator, we first had to create custom fields that this validator can benefit from. Luckily flask-restplus comes with a great API for creating custom fields.
So we quickly created custom fields for all common fields (Integer, String) and more specific fields like Email, Uri and Color.
Creating these specific fields were a huge advantage as now we can show proper example for each field types in the Swagger UI.
Consider the above code; now when we use
Now we needed a way to validate these fields. For that, what we did was to create a
validate method in each of the field-classes.
validate method would get the value and check if it was valid. Consider the following code -
Once each of the field had their validate methods, we created a
validate_payload() function that uses the API model and compares it with the payload.
It will first check if all required keys are present in the payload or not.
When that is true, it finally validates each field’s value using their field’s class
CustomField is the base class that each of the custom fields mentioned above inherit. So checking if
field was an instance of
CustomField is enough to know if it is
a custom field or not.
Other thing that may look weird in the above code is use of
fields.List. If you look closely, I have added this to support custom fields inside lists.
So if you have used a custom field in a list, it will also work too. But obviously, this only supports single level lists for now.
The thing is we didn’t needed more than that so I let it go.
This basically sums up how we are validating input payloads at Open Event. Of course this is very basic but we will keep on improving it as the project progresses. Stay tuned to opev blog if you want to be in touch with the progress of the project.
Links to full code at the time of writing this post are -
I hope you found this post useful. Thanks for reading.