We now rely on Cookiecutter instead of the deprecated Pyramid scaffolding feature:
$ cookiecutter gh:Cornices/cookiecutter-cornice
The Sphinx extension now lives in a separate package, that must be installed:
pip install cornice_sphinx
Before in your docs/conf.py
:
Now:
Validators now receive the kwargs of the related service definition.
Before:
def has_payed(request):
if 'paid' not in request.GET:
request.errors.add('body', 'paid', 'You must pay!')
Now:
def has_payed(request, **kwargs):
free_access = kwargs.get('free_access')
if not free_access and 'paid' not in request.GET:
request.errors.add('body', 'paid', 'You must pay!')
Colander schema validation now requires an explicit validator on the service view definition.
Before:
class SignupSchema(colander.MappingSchema):
username = colander.SchemaNode(colander.String())
@signup.post(schema=SignupSchema)
def signup_post(request):
username = request.validated['username']
return {'success': True}
Now:
from cornice.validators import colander_body_validator
class SignupSchema(colander.MappingSchema):
username = colander.SchemaNode(colander.String())
@signup.post(schema=SignupSchema, validators=(colander_body_validator,))
def signup_postt(request):
username = request.validated['username']
return {'success': True}
This makes declarations a bit more verbose, but decorrelates Cornice from Colander. Now any validation library can be used.
If you have complex use-cases where data has to be validated accross several locations
of the request (like querystring, body etc.), Cornice provides a validator that
takes an additionnal level of mapping for body
, querystring
, path
or headers
instead of the former location
attribute on schema fields.
The request.validated
hences reflects this additional level.
Before:
class SignupSchema(colander.MappingSchema):
username = colander.SchemaNode(colander.String(), location='body')
referrer = colander.SchemaNode(colander.String(), location='querystring',
missing=colander.drop)
@signup.post(schema=SignupSchema)
def signup_post(request):
username = request.validated['username']
referrer = request.validated['referrer']
return {'success': True}
Now:
from cornice.validators import colander_validator
class Querystring(colander.MappingSchema):
referrer = colander.SchemaNode(colander.String(), missing=colander.drop)
class Payload(colander.MappingSchema):
username = colander.SchemaNode(colander.String())
class SignupSchema(colander.MappingSchema):
body = Payload()
querystring = Querystring()
signup = cornice.Service()
@signup.post(schema=SignupSchema, validators=(colander_validator,))
def signup_post(request):
username = request.validated['body']['username']
referrer = request.validated['querystring']['referrer']
return {'success': True}
This now allows to have validation at the schema level that validates data from several locations:
class SignupSchema(colander.MappingSchema):
body = Payload()
querystring = Querystring()
def deserialize(self, cstruct=colander.null):
appstruct = super(SignupSchema, self).deserialize(cstruct)
username = appstruct['body']['username']
referrer = appstruct['querystring'].get('referrer')
if username == referred:
self.raise_invalid('Referrer cannot be the same as username')
return appstruct
error_handler
callback of services now receives a request
object instead of errors
.Before:
def xml_error(errors):
request = errors.request
...
Now:
def xml_error(request):
errors = request.errors
...
The support of config.add_deserializer()
and config.registry.cornice_deserializers
was dropped.
The schema
argument of services is now treated as service kwarg.
The service.schemas_for()
method was dropped as well as the service.schemas
property.
Before:
schema = service.schemas_for(method="POST")
Now:
schema = [kwargs['schema'] for method, view, kwargs in service.definitions
if method == "POST"][0]