This commit is contained in:
Alexis Metaireau 2011-12-07 14:55:07 +01:00
parent 53032588ca
commit 377827749c

View file

@ -1,17 +1,17 @@
Introducing cornice Introducing Cornice
################### ###################
:date: 06/12/2011 :date: 06/12/2011
Wow, already my third working day at mozilla. Since Monday, I've been working with Wow, already my third working day at mozilla. Since Monday, I've been working with
Tarek Ziadé, on a pyramid REST-ish toolkit named `cornice <https://github.com/mozilla-services/cornice>`_. Tarek Ziadé, on a pyramid REST-ish toolkit named `Cornice <https://github.com/mozilla-services/Cornice>`_.
Its goal is to take all the hard bits appart from you when implementing a web Its goal is to take care for you of what you're usually missing so you can
service, so you can focus on what's important. Cornice provides you facilities focus on what's important. Cornice provides you facilities
for validation of any kind. for validation of any kind.
The goal is to simplify your work, but we don't want to reinvent the wheel, so The goal is to simplify your work, but we don't want to reinvent the wheel, so
it is easily pluggable with validations frameworks, such as Collander. it is easily pluggable with validations frameworks, such as Colander.
Handling errors and validation Handling errors and validation
============================== ==============================
@ -25,7 +25,7 @@ We have changed the way errors are handled. Here is how it works:
def is_awesome(request): def is_awesome(request):
if not 'awesome' in request.GET: if not 'awesome' in request.GET:
request.errors.add('body', 'awesome', request.errors.add('query', 'awesome',
'the awesome parameter is required') 'the awesome parameter is required')
@ -36,18 +36,17 @@ We have changed the way errors are handled. Here is how it works:
All the errors collected during the validation process, or after, are collected All the errors collected during the validation process, or after, are collected
before returning the request. If any, a error 400 is fired up, with the list of before returning the request. If any, a error 400 is fired up, with the list of
problems encoutred encoded as a nice json list (we plan to support multiple problems encountered returned as a nice json list response (we plan to support
formats in the future) multiple formats in the future)
As you might have seen, `request.errors.add` takes three parameters: **location**, As you might have seen, `request.errors.add` takes three parameters: **location**,
**name** and **description**. **name** and **description**.
**location** is where the error arised. It can either be "body", "query", "headers" **location** is where the error is located in the request. It can either be "body",
or "path". **name** is the name of the variable causing problem, if any, and "query", "headers" or "path". **name** is the name of the variable causing
**description** contains a more detailled message. problem, if any, and **description** contains a more detailled message.
Let's run this simple service, with `bin/paster serve` and send some queries to Let's run this simple service and send some queries to it::
it::
$ curl -v http://127.0.0.1:5000/service $ curl -v http://127.0.0.1:5000/service
> GET /service HTTP/1.1 > GET /service HTTP/1.1
@ -57,7 +56,7 @@ it::
* HTTP 1.0, assume close after body * HTTP 1.0, assume close after body
< HTTP/1.0 400 Bad Request < HTTP/1.0 400 Bad Request
< Content-Type: application/json; charset=UTF-8 < Content-Type: application/json; charset=UTF-8
[{"location": "body", "name": "awesome", "description": "You lack awesomeness!"} [{"location": "query", "name": "awesome", "description": "You lack awesomeness!"}
I've removed the extra clutter from the curl's output, but you got the general idea. I've removed the extra clutter from the curl's output, but you got the general idea.
@ -67,8 +66,8 @@ The content returned is in JSON, and I know exactly what I have to do: add an
$ curl http://127.0.0.1:5000/service?awesome=yeah $ curl http://127.0.0.1:5000/service?awesome=yeah
{"test": "yay!"} {"test": "yay!"}
Validators can also attach extra information about validations to the request, Validators can also convert parts of the request and store the converted value
using `request.validated`. It is a standard dict automatically attached to the in `request.validated`. It is a standard dict automatically attached to the
requests. requests.
For instance, in our validator, we can chose to validate the parameter passed For instance, in our validator, we can chose to validate the parameter passed
@ -81,7 +80,7 @@ and use it in the body of the webservice:
def is_awesome(request): def is_awesome(request):
if not 'awesome' in request.GET: if not 'awesome' in request.GET:
request.errors.add('body', 'awesome', request.errors.add('query', 'awesome',
'the awesome parameter is required') 'the awesome parameter is required')
else: else:
request.validated['awesome'] = 'awesome ' + request.GET['awesome'] request.validated['awesome'] = 'awesome ' + request.GET['awesome']
@ -91,6 +90,8 @@ and use it in the body of the webservice:
def get1(request): def get1(request):
return {"test": request.validated['awesome']} return {"test": request.validated['awesome']}
The output would look like this:
:: ::
curl http://127.0.0.1:5000/service?awesome=yeah curl http://127.0.0.1:5000/service?awesome=yeah
@ -105,8 +106,8 @@ The HTTP spec defines a **Accept** header the client can send so the response
is encoded the right way. A resource, available at an URL, can be available in is encoded the right way. A resource, available at an URL, can be available in
different formats. This is especially true for web services. different formats. This is especially true for web services.
Cornice can help you to deal with this. The services you define can tell which Cornice can help you dealing with this. The services you define can tell which
content-types they can deal with, and this will be checked against the `Content-Types` values they can deal with and this will be checked against the
**Accept** headers sent by the client. **Accept** headers sent by the client.
Let's refine a bit our previous example, by specifying which content-types are Let's refine a bit our previous example, by specifying which content-types are
@ -118,8 +119,8 @@ supported, using the `accept` parameter:
def get1(request): def get1(request):
return {"test": "yay!"} return {"test": "yay!"}
Now, if you specifically ask for XML, for instance, cornice will throw a 406 Now, if you specifically ask for XML, Cornice will throw a 406 with the list of
with the list of accepted content-types:: accepted `Content-Type` values::
$ curl -vH "Accept: application/xml" http://127.0.0.1:5000/service $ curl -vH "Accept: application/xml" http://127.0.0.1:5000/service
> GET /service HTTP/1.1 > GET /service HTTP/1.1
@ -137,3 +138,9 @@ Building your documentation automatically
========================================= =========================================
XXX XXX
Yay, how can I get it?
======================
What's next
===========