Skip to content

Commit

Permalink
Merge pull request #397 from Cornices/several-improvements-in-docs
Browse files Browse the repository at this point in the history
Fixes #204
Fixes #304
  • Loading branch information
leplatrem committed Oct 20, 2016
2 parents 01cea7d + d33400c commit fe5de79
Show file tree
Hide file tree
Showing 19 changed files with 451 additions and 307 deletions.
33 changes: 19 additions & 14 deletions cornice/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ def resource(depth=2, **kw):
"""Class decorator to declare resources.
All the methods of this class named by the name of HTTP resources
will be used as such. You can also prefix them by "collection_" and they
will be treated as HTTP methods for the given collection path
will be used as such. You can also prefix them by ``"collection_"`` and
they will be treated as HTTP methods for the given collection path
(collection_path), if any.
:param depth:
Expand All @@ -38,8 +38,8 @@ def add_resource(klass, depth=1, **kw):
"""Function to declare resources of a Class.
All the methods of this class named by the name of HTTP resources
will be used as such. You can also prefix them by "collection_" and they
will be treated as HTTP methods for the given collection path
will be used as such. You can also prefix them by ``"collection_"`` and
they will be treated as HTTP methods for the given collection path
(collection_path), if any.
:param klass:
Expand All @@ -52,7 +52,10 @@ def add_resource(klass, depth=1, **kw):
Keyword arguments configuring the resource.
Here is an example::
Here is an example:
.. code-block:: python
class User(object):
pass
Expand Down Expand Up @@ -149,19 +152,21 @@ def add_view(func, **kw):
Example:
class User(object):
.. code-block:: python
def __init__(self, request):
self.request = request
class User(object):
def __init__(self, request):
self.request = request
def collection_get(self):
return {'users': _USERS.keys()}
def collection_get(self):
return {'users': _USERS.keys()}
def get(self):
return _USERS.get(int(self.request.matchdict['id']))
def get(self):
return _USERS.get(int(self.request.matchdict['id']))
add_view(User.get, renderer='json')
add_resource(User, collection_path='/users', path='/users/{id}')
add_view(User.get, renderer='json')
add_resource(User, collection_path='/users', path='/users/{id}')
"""
# XXX needed in py2 to set on instancemethod
if hasattr(func, '__func__'):
Expand Down
2 changes: 1 addition & 1 deletion cornice/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ class Service(object):
given request). Exclusive with the 'factory' option.
:param permission:
As for :ref:`pyramid.config.Configurator.add_view`.
As for ``pyramid.config.Configurator.add_view()``.
Note: `acl` and `permission` can also be applied
to instance method decorators such as :meth:`~get` and :meth:`~put`.
Expand Down
1 change: 1 addition & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
mozilla-sphinx-theme==0.2
cornice_sphinx
colander
19 changes: 19 additions & 0 deletions docs/source/api.rst
Original file line number Diff line number Diff line change
@@ -1,9 +1,28 @@
Cornice API
###########

Service
=======

.. py:module:: cornice.service
This document describes the methods proposed by cornice. It is
automatically generated from the source code.

.. autoclass:: cornice.service.Service
.. autofunction:: cornice.service.decorate_view


Resource
========

.. autofunction:: cornice.resource.resource
.. autofunction:: cornice.resource.view
.. autofunction:: cornice.resource.add_view
.. autofunction:: cornice.resource.add_resource


Errors
======

.. autoclass:: cornice.errors.Errors
71 changes: 0 additions & 71 deletions docs/source/builtin-validation.rst

This file was deleted.

16 changes: 0 additions & 16 deletions docs/source/config.rst

This file was deleted.

13 changes: 0 additions & 13 deletions docs/source/exampledoc.rst

This file was deleted.

43 changes: 34 additions & 9 deletions docs/source/exhaustive_list.rst
Original file line number Diff line number Diff line change
@@ -1,33 +1,36 @@
Exhaustive list of the validations provided by Cornice
######################################################
Exhaustive features list
########################

As you may have noticed, Cornice does some validation for you. This document
aims at documenting all those behaviours so you are not surprised if Cornice
does it for you without noticing.

Validation
==========

Errors
======
~~~~~~

When validating contents, cornice will automatically throw a 400 error if the
When validating contents, Cornice will automatically throw a 400 error if the
data is invalid. Along with the 400 error, the body will contain a JSON dict
which can be parsed to know more about the problems encountered.

Method not allowed
==================
~~~~~~~~~~~~~~~~~~

In cornice, one path equals one service. If you call a path with the wrong
method, a `405 Method Not Allowed` error will be thrown (and not a 404), like
specified in the HTTP specification.

Authorization
=============
~~~~~~~~~~~~~

Authorization can be done using the `acl` parameter. If the authentication or
the authorization fails at this stage, a 401 or 403 error is returned,
depending on the cases.

Content negotiation
===================
~~~~~~~~~~~~~~~~~~~

This relates to **response body** internet media types aka. egress content types.

Expand All @@ -38,7 +41,7 @@ invalid media type via `Accept` header, cornice will return a
response content types for the particular URI and method.

Request media type
==================
~~~~~~~~~~~~~~~~~~

This relates to **request body** internet media types aka. ingress content types.

Expand All @@ -49,7 +52,7 @@ sends a request with an invalid `Content-Type` header, cornice will return a
request content types for the particular URI and method.

Warning when returning JSON lists
=================================
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

JSON lists are subject to security threats, as defined
`in this document <http://haacked.com/archive/2009/06/25/json-hijacking.aspx>`_.
Expand All @@ -58,3 +61,25 @@ however prevent you from returning the array.

This behaviour can be disabled if needed (it can be removed from the list of
default filters)


URL prefix
==========

It is possible to set a prefix for all your routes. For instance, if you want to
prefix all your URIs by ``/v1/``.

.. code-block:: python
config.route_prefix = 'v2'
config.include("cornice")
CORS
====

Cornice can add CORS (Cross Origin Resource Sharing) support to your services.
When enabled, it will define the appropriate views (``OPTIONS`` methods)
and validators (headers etc.).

See :ref:`more details...<service-cors>`
4 changes: 3 additions & 1 deletion docs/source/faq.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Sometimes, you will need to register your own exception handlers, and Cornice
might get on your way.

You can disable the exception handling by using the `handle_exceptions`
setting in your configuration file or in your main app::
setting in your configuration file or in your main app:

.. code-block:: python
config.add_settings(handle_exceptions=False)
31 changes: 11 additions & 20 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,19 @@ Show me some code!
==================

A **full** Cornice WGSI application looks like this (this example is taken from
the `demoapp project <https://github.com/mozilla-services/demoapp>`_)::
the `demoapp project <https://github.com/Cornices/examples>`_)::

from collections import defaultdict

from pyramid.exceptions import Forbidden
from pyramid.security import authenticated_userid, effective_principals
from pyramid.httpexceptions import HTTPForbidden
from pyramid.view import view_config

from cornice import Service


info_desc = """\
This service is useful to get and set data for a user.
"""


user_info = Service(name='users', path='/{username}/info',
description=info_desc)
user_info = Service(name='users',
path='/{username}/info',
description='Get and set user data.')

_USERS = defaultdict(dict)

Expand All @@ -52,30 +47,28 @@ the `demoapp project <https://github.com/mozilla-services/demoapp>`_)::

Returns *True* or *False*.
"""
username = authenticated_userid(request)
username = request.authenticated_userid
if request.matchdict["username"] != username:
raise Forbidden()
raise HTTPForbidden()
_USERS[username] = request.json_body
return {'success': True}


@view_config(route_name="whoami", permission="authenticated", renderer="json")
def whoami(request):
"""View returning the authenticated user's credentials."""
username = authenticated_userid(request)
principals = effective_principals(request)
username = request.authenticated_userid
principals = request.effective_principals
return {"username": username, "principals": principals}

What Cornice will do for you here is:

- automatically raise a 405 if a DELETE or a PUT is called on
**/{username}/info**
- automatically generate your doc via a Sphinx directive.
- provide a validation framework that will return a nice JSON structure
in Bad Request 400 responses explaining what's wrong.
- provide an acceptable **Content-Type** whenever you send an HTTP "Accept"
header
to it, resulting in a *406 Not Acceptable* with the list of acceptable ones
header to it, resulting in a *406 Not Acceptable* with the list of acceptable ones
if it can't answer.

Please follow up with :doc:`exhaustive_list` to get the picture.
Expand All @@ -89,14 +82,12 @@ Documentation content

quickstart
tutorial
config
services
resources
validation
builtin-validation
schema
testing
exhaustive_list
exampledoc
api
internals
faq
Expand Down

0 comments on commit fe5de79

Please sign in to comment.