Cerberus validation support for Morepath
Project description
more.cerberus: validation and normalization support for Morepath
This package provides Morepath integration for the Cerberus data validation library:
Cerberus can automate user input validation and normalization in a HTTP API.
Schema
You can define a schema simply as a Python dict:
user_schema = {
'name': {'type': 'string', 'minlength' : 3, 'required': True},
'age': {'type': 'integer', 'min': 0, 'required': True}
}
Altenatively you can define the schema in yaml and load it with pyyaml:
user:
name:
type: string
minlength: 3
required: true
age:
type: integer
min: 0
required: true
import yaml
with open('schema.yml') as schema:
schema = yaml.load(schema)
user_schema = schema['user']
Validate
The more.cerberus integration helps with validation of the request body as it is POSTed or PUT to a view. First we must create a loader for our schema:
from more.cerberus import loader
user_schema_load = loader(user_schema)
We can use this loader to handle a PUT or POST request for instance:
@App.json(model=User, request_method='POST', load=user_schema_load)
def user_post(self, request, json):
# json is now a validated and normalized dict of whatever got
# POST onto this view that you can use to update
# self
Update models
By default in PUT or PATCH requests the load function sets the update flag of the validate() method to True, so required fields won’t be checked. For other requests like POST update is False.
You can set this manually by passing the update argument to the load function:
user_schema_load = loader(user_schema, update=False)
@App.json(model=User, request_method='PUT', load=user_schema_load)
def user_put(self, request, json):
Customize the Validator
With Cerberus you can customize the rules, data types, validators, coercers (for normalization) and default setters by subclassing CerberusValidator:
import re
from more.cerberus import CerberusValidator
class CustomValidator(CerberusValidator):
def _check_with_validate_email(self, field, value):
match = re.match(
'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$',value
)
if match == None:
self._error(field, 'Not valid email')
def _normalize_coerce_normalize_email(self, value):
parts = value.split('@')
if len(parts) != 2:
return value
else:
domain = parts[1].lower
if domain == 'googlemail.com':
domain = 'gmail.com'
return parts[0] + '@' + domain
You have to pass the custom Validator class to the load function:
user_schema_load = loader(user_schema, validator=CustomValidator)
Now you can use the new email validator and normalizer in your schema:
user_schema = {
'name': {
'type': 'string',
'minlength' : 3,
'required': True,
},
'email': {
'type': 'string',
'check_with': 'validate_email',
'coerce': 'normalize_email',
'required': True,
}
}
or with YAML:
user:
name:
type: string
minlength: 3
required: true
email:
type: string
check_with: validate_email
coerce: normalize_email
required: true
For more information how to customize the Validator take a look at the Cerberus documentation.
Use the request or app instance in your custom validator
In CerberusValidator you can access the request through self.request and the app through self.request.app. Like this you can use e.g. Morepath settings and services when extending rules.
Here an example from auth-boilerplate for custom email validation and normalization using a service based on email_validator:
from more.cerberus import CerberusValidator
from email_validator import EmailSyntaxError, EmailUndeliverableError
class Validator(CerberusValidator):
def _check_with_verify_email(self, field, value):
email_validation_service = self.request.app.service(
name='email_validation'
)
try:
email_validation_service.verify(value)
except EmailSyntaxError:
self._error(field, 'Not valid email')
except EmailUndeliverableError:
self._error(field, 'Email could not be delivered')
def _normalize_coerce_normalize_email(self, value):
email_validation_service = self.request.app.service(
name='email_validation'
)
return email_validation_service.normalize(value)
Error handling
If validation fails due to a validation error (a required field is missing, or a field is of the wrong datatype, for instance), you want to show some kind of error message. The load function created by more.cerberus raises the more.cerberus.ValidationError exception in case of errors.
This exception object has an errors attribute with the validation errors. You must define an exception view for it, otherwise validation errors are returned as “500 internal server error” to API users.
This package provides a default exception view implementation. If you subclass your application from more.cerberus.CerberusApp then you get a default error view for ValidationError that has a 422 status code with a JSON response with the Cerberus errors structure:
from more.cerberus import CerberusApp
class App(CerberusApp):
pass
Now your app has reasonable error handling built-in.
If you want a different error view you can instead create it by yourself, e.g.:
from more.cerberus.error import ValidationError
from .app import App
@App.json(model=ValidationError)
def validation_error(self, request):
@request.after
def set_status(response):
response.status = 422
errors = list(self.errors.values())[0][0]
return {
'errors': errors
}
This could be used to extract the errors from a schema wrapped into a dictionary like:
article-schema:
article:
type: dict
schema:
title:
type: string
required: true
body:
type: string
required: true
CHANGES
0.3 (2020-04-26)
Removed: Removed support for Python 2.
You have to upgrade to Python 3 if you want to use this version.
Added support for Python 3.7 and 3.8 and PyPy 3.6.
Make Python 3.7 the default testing environment.
Upgrade Cerberus to version 1.3.2.
Add integration for the Black code formatter.
0.2 (2018-02-11)
Add Python 3.6 support.
Add example for creating a custom error view to README.
Some smaller fixes.
0.1 (2017-03-17)
initial public release.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Hashes for more.cerberus-0.3-py2.py3-none-any.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | b40d46c9f0a428680dd6ef33bfd525004beafe6087c3330f67d98234e4137cae |
|
MD5 | 6916872f6cc4075913b5894509189582 |
|
BLAKE2b-256 | 12e4c6512f6aeed0510d31d5155aba6406c8c7da86808293053ee50a1159e07b |