Server validation in Flask API with JSON schema
Validation in the API world means checking if the data send is good or not. You never can entirely rely on having only a client-side validation. Because you don’t know what’s happening on the client, you can’t trust the data you receive. Even if you have a private API, someone could still send you invalid requests.
Server-side validation implied checking multiple things :
- what are the expected properties
- does they have the good format/type
- is the property required
Json schema
The JSON Schema is a way to describe any instance of JSON data, like the ones found in our HTTP request or response.
The keyword type will restrict your property to a certain type. There is several possible values :
- string
- number
- object
- array
- boolean
- null
Numbers
"my_param": { "type": "number" }
You can ensure that you parameter is inside a certain range with additional parameters :
- x ≥
minimum
- x >
exclusiveMinimum
- x ≤
maximum
- x <
exclusiveMaximum
"my_param": {
"type": "number",
"minimum": 0,
"maximum": 100
}
Strings
"my_param": { "type": "string" }
There is also some optional parameters :
- minLength (minimum numbers of characters my string can contain)
- maxLength (maximum numbers of characters my string can contain)
- Pattern (it’s a regex, will be consider as valid if the string match the regex)
"firstname": {
"type": "string",
"minLength": 2,
"maxLength": 50
}
Objects
"my_param": { "type": "object" }
With properties you can describe all the variables inside of your object.
{
"type": "object",
"properties": {
"number": { "type": "number" },
"street_name": { "type": "string" },
},
"required": ["street_name"]
}
One important keyword in required. It will make sure that some of the values are send in the request.
Arrays
"my_param": { "type": "array" }
You can apply validation to the elements of the array if they all follow the same schema. You can check length of the array minItems and maxItems.
"my_param": {
"type": "array,
"minItems": 3,
"items: {
"type": "number"
}
}
You can create list of complex elements, and have list of objects that themselves contains lists…
Booleans
"my_param": { "type": "boolean" }
No real surprise here, the value can either be True or False
Null
"my_param": { "type": "null" }
Is used to represent a missing value, it’s equivalent to None in python
Multiple types
Maybe a parameter can have multiple possible type, for example string and None. When the value send can be either empty or a string.
"my_param": { "type": ["string, "null"] }
Validation with Flask
The package
There is several python packages that will do validation based on JSON schema. I personally use flask-expects-json.
To install it :
pip install flask-expects-json
How it work
The package simply works as a decorator for your flask endpoints.
schema = {
"type": "object",
"properties": {
"name": { "type": "string" },
"email": { "type": "string" }
},
"required": ["email"]
}@app.route('/', methods=['POST'])
@expects_json(schema)
def example_endpoint():
...
If the request received does not correspond to the schema it will raise an error. And a 400 error will be send as a response.-
Skip validations methods
If your endpoint has several method, you can ignore the validation for some of them.
@app.route('/', methods=['GET', 'POST'])
@expects_json(schema, ignore_for=['GET'])
def example():
return
There is other useful keywords in the json-schema. I’ve only covered here the most useful ones.