mirror of
https://github.com/almet/notmyidea.git
synced 2025-04-28 19:42:37 +02:00
- Added the ability to display book cover for the category "Lectures" if ISBN cover is available. - Moved author's name into a small tag for better hierarchy and readability. - Implemented a feature to indicate link sizes depending on the number of articles associated with a given tag. - Implemented a mini footer element displaying an RSS feed icon. - Improved category display using description dictionary. - Added a new plugin "isbn_downloader" to fetch ISBN information when needed. - Included the count of articles for each category. - Implemented changes for better layout and readability of tags and categories. - Adjusted the layout of the webpage, improving the overall look of the page. - Included "requests" in the requirements.txt for supplanting dependencies required by the new plugin and/or features.
172 lines
5.3 KiB
Markdown
172 lines
5.3 KiB
Markdown
# Introducing Cornice
|
|
|
|
Wow, already my third working day at Mozilla. Since Monday, I've been
|
|
working with [Tarek Ziadé](http://ziade.org), on a pyramid REST-ish
|
|
toolkit named [Cornice](https://github.com/mozilla-services/cornice).
|
|
|
|
Its goal is to take care for you of what you're usually missing so you
|
|
can focus on what's important. Cornice provides you facilities for
|
|
validation of any kind.
|
|
|
|
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
|
|
[Colander](http://docs.pylonsproject.org/projects/colander/en/latest/).
|
|
|
|
## Handling errors and validation
|
|
|
|
Here is how it works:
|
|
|
|
```python
|
|
|
|
service = Service(name="service", path="/service")
|
|
|
|
|
|
def is_awesome(request):
|
|
if not 'awesome' in request.GET:
|
|
request.errors.add('query', 'awesome',
|
|
'the awesome parameter is required')
|
|
|
|
|
|
@service.get(validator=is_awesome)
|
|
def get1(request):
|
|
return {"test": "yay!"}
|
|
```
|
|
|
|
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 problems encountered returned as a nice json list
|
|
response (we plan to support multiple formats in the future)
|
|
|
|
As you might have seen, request.errors.add takes three parameters:
|
|
**location**, **name** and **description**.
|
|
|
|
**location** is where the error is located in the request. It can either
|
|
be "body", "query", "headers" or "path". **name** is the name of the
|
|
variable causing problem, if any, and **description** contains a more
|
|
detailed message.
|
|
|
|
Let's run this simple service and send some queries to it:
|
|
|
|
$ curl -v http://127.0.0.1:5000/service
|
|
> GET /service HTTP/1.1
|
|
> Host: 127.0.0.1:5000
|
|
> Accept: */*
|
|
>
|
|
* HTTP 1.0, assume close after body
|
|
< HTTP/1.0 400 Bad Request
|
|
< Content-Type: application/json; charset=UTF-8
|
|
[{"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.
|
|
|
|
The content returned is in JSON, and I know exactly what I have to do:
|
|
add an "awesome" parameter in my query. Let's do it again:
|
|
|
|
$ curl http://127.0.0.1:5000/service?awesome=yeah
|
|
{"test": "yay!"}
|
|
|
|
Validators can also convert parts of the request and store the converted
|
|
value in request.validated. It is a standard dict automatically attached
|
|
to the requests.
|
|
|
|
For instance, in our validator, we can chose to validate the parameter
|
|
passed and use it in the body of the webservice:
|
|
|
|
```python
|
|
|
|
service = Service(name="service", path="/service")
|
|
|
|
|
|
def is_awesome(request):
|
|
if not 'awesome' in request.GET:
|
|
request.errors.add('query', 'awesome',
|
|
'the awesome parameter is required')
|
|
else:
|
|
request.validated['awesome'] = 'awesome ' + request.GET['awesome']
|
|
|
|
|
|
@service.get(validator=is_awesome)
|
|
def get1(request):
|
|
return {"test": request.validated['awesome']}
|
|
```
|
|
|
|
The output would look like this:
|
|
|
|
curl http://127.0.0.1:5000/service?awesome=yeah
|
|
{"test": "awesome yeah"}
|
|
|
|
## Dealing with "Accept" headers
|
|
|
|
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 different formats. This is especially true for web
|
|
services.
|
|
|
|
Cornice can help you dealing with this. The services you define can tell
|
|
which Content-Type values they can deal with and this will be checked
|
|
against the **Accept** headers sent by the client.
|
|
|
|
Let's refine a bit our previous example, by specifying which
|
|
content-types are supported, using the accept
|
|
parameter:
|
|
|
|
```python
|
|
|
|
@service.get(validator=is_awesome, accept=("application/json", "text/json"))
|
|
def get1(request):
|
|
return {"test": "yay!"}
|
|
```
|
|
|
|
Now, if you specifically ask for XML, Cornice will throw a 406 with the
|
|
list of accepted Content-Type values:
|
|
|
|
$ curl -vH "Accept: application/xml" http://127.0.0.1:5000/service
|
|
> GET /service HTTP/1.1
|
|
> Host: 127.0.0.1:5000
|
|
> Accept: application/xml
|
|
>
|
|
< HTTP/1.0 406 Not Acceptable
|
|
< Content-Type: application/json; charset=UTF-8
|
|
< Content-Length: 33
|
|
<
|
|
["application/json", "text/json"]
|
|
|
|
## Building your documentation automatically
|
|
|
|
writing documentation for web services can be painful, especially when
|
|
your services evolve. Cornice provides a sphinx directive to
|
|
automatically document your API in your docs.
|
|
|
|
```
|
|
rst
|
|
.. services::
|
|
:package: coolapp
|
|
:service: quote
|
|
```
|
|
|
|
Here is an example of what a generated page looks like:
|
|
<http://packages.python.org/cornice/exampledoc.html>
|
|
|
|
## Yay\! How can I get it?
|
|
|
|
We just cut a 0.4 release, so it's available at
|
|
<http://pypi.python.org/pypi/cornice> You can install it easily using
|
|
pip, for instance:
|
|
|
|
$ pip install cornice
|
|
|
|
You can also have a look at the documentation at
|
|
<http://packages.python.org/cornice/>
|
|
|
|
## What's next?
|
|
|
|
We try to make our best to find how Cornice can help you build better
|
|
web services. Cool features we want for the future include the automatic
|
|
publication of a static definition of the services, so it can be used by
|
|
clients to discover services in a nice way.
|
|
|
|
Of course, we are open to all your ideas and patches\! If you feel
|
|
haskish and want to see the sources, [go grab them on
|
|
github](https://github.com/mozilla-services/cornice) , commit and send
|
|
us a pull request\!
|