Skip to content

Commit

Permalink
Support for manipulation of outbound documents via callback functions.
Browse files Browse the repository at this point in the history
The ``on_getting``, ``on_getting_<resource>`` and ``on_getting_item`` event
hooks are raised when documents have just been read from the database and are
about to be sent to the client. Registered callback functions can eventually
manipulate the documents as needed.

Please be aware that ``last_modified`` and ``etag`` headers will always be
consistent with the state of the documents on the database (they  won't be
updated to reflect changes eventually applied by the callback functions).

Closes #65.
  • Loading branch information
nicolaiarocci committed Jul 8, 2013
1 parent eeb3683 commit 2842077
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 8 deletions.
7 changes: 7 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ Version 0.0.8

Not released yet.

- ``on_getting``, ``on_getting_<resource>`` and ``on_getting_item`` event
hooks. These events are raised when documents have just been read from the
database and are about to be sent to the client. Registered callback
functions can eventually manipulate the documents as needed. Please be aware
that ``last_modified`` and ``etag`` headers will always be consistent with
the state of the documents on the database (they won't be updated to reflect
changes eventually applied by the callback functions). Closes #65.
- Documentation fix: ``AUTH_USERFIELD_NAME`` renamed to ``AUTH_USERNAME_FIELD``
(Julien Barbot).
- Responses to GET requests for resource endpoints now include a ``last`` item
Expand Down
29 changes: 21 additions & 8 deletions docs/features.rst
Original file line number Diff line number Diff line change
Expand Up @@ -526,12 +526,12 @@ payload as arguments.
>>> app.run()
Manipulating documents on insertion
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There is also support for ``on_posting`` and ``on_posting_<resource>`` event
hooks, raised when documents are about to be stored in the database. Callback
functions could hook to these events to arbitrarily add new fields, or edit
existing ones.
Manipulating inbound documents
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
There is also support for ``on_posting(resource, documents)`` and
``on_posting_<resource>(documents)`` event hooks, raised when documents are
about to be stored in the database. Callback functions could hook to these
events to arbitrarily add new fields, or edit existing ones.

.. code-block:: pycon
Expand All @@ -551,11 +551,24 @@ existing ones.
``on_posting_<resource>`` is raised when the `<resource>` endpoint has been hit
with a POST request. In both circumstances the event will be raised only if at
least one document passed validation and is going to be inserted. `documents`
is a list, and only contains documents ready for insertion (payload
documents that did not pass validation are not included).
is a list, and only contains documents ready for insertion (payload documents
that did not pass validation are not included).

To provide seamless event handling features, Eve relies on the Events_ package.

Manipulationg outbound documents
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ``on_getting(resource, documents)``, ``on_getting_<resource>(documents)``
and ``on_getting_item(resource, _id, document)`` event hooks are raised when
documents have just been read from the database and are about to be sent to the
client. Registered callback functions can eventually manipulate the documents
as needed.

Please be aware that ``last_modified`` and ``etag`` headers will always be
consistent with the state of the documents on the database (they won't be
updated to reflect changes eventually applied by the callback functions).


Rate Limiting
-------------
API rate limiting is supported on a per-user/method basis. You can set the
Expand Down
26 changes: 26 additions & 0 deletions eve/methods/get.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ def get(resource):
:param resource: the name of the resource.
.. versionchanged: 0.0.8
'on_getting' and 'on_getting_<resource>' events are raised when
documents have been read from the database and are about to be sent to
the client.
.. versionchanged:: 0.0.6
Support for HEAD requests.
Expand Down Expand Up @@ -73,6 +78,15 @@ def get(resource):
else:
status = 200
last_modified = last_updated if last_updated > _epoch() else None

# notify registered callback functions. Please note that, should the
# functions modify the documents, the last_modified and etag won't be
# updated to reflect the changes (they always reflect the documents
# state on the database.)

getattr(app, "on_getting")(resource, documents)
getattr(app, "on_getting_%s" % resource)(documents)

response['_items'] = documents
response['_links'] = _pagination_links(resource, req, cursor.count())

Expand All @@ -88,6 +102,10 @@ def getitem(resource, **lookup):
:param resource: the name of the resource to which the document belongs.
:param **lookup: the lookup query.
.. versionchanged: 0.0.8
'on_getting_item' event is raised when a document has been read from the
database and is about to be sent to the client.
.. versionchanged:: 0.0.7
Support for Rate-Limiting.
Expand Down Expand Up @@ -136,6 +154,14 @@ def getitem(resource, **lookup):
'collection': collection_link(resource),
'parent': home_link()
}

# notify registered callback functions. Please note that, should the
# functions modify the document, last_modified and etag won't be
# updated to reflect the changes (they always reflect the documents
# state on the database).
getattr(app, "on_getting_item")(resource, document[config.ID_FIELD],
document)

response.update(document)
return response, last_modified, document['etag'], 200

Expand Down
27 changes: 27 additions & 0 deletions eve/tests/renders.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ def test_CORS_OPTIONS(self):


class TestEventHooks(TestBase):
#TODO not sure this is the right place for this class really.

def setUp(self):
super(TestEventHooks, self).setUp()
Expand Down Expand Up @@ -195,6 +196,32 @@ def resource_hook(documents):
self.post()
self.assertTrue(self.passed)

def test_on_getting(self):
def general_hook(resource, documents):
self.assertEqual(resource, self.known_resource)
self.assertEqual(len(documents), 25)
self.passed = True
self.app.on_getting += general_hook
self.test_client.get(self.known_resource_url)
self.assertTrue(self.passed)

def test_on_getting_resource(self):
def resource_hook(documents):
self.assertEqual(len(documents), 25)
self.passed = True
self.app.on_getting_contacts += resource_hook
self.test_client.get(self.known_resource_url)
self.assertTrue(self.passed)

def test_on_getting_item(self):
def item_hook(resource, _id, document):
print _id, self.item_id
self.assertEqual(str(_id), self.item_id)
self.passed = True
self.app.on_getting_item += item_hook
self.test_client.get(self.item_id_url)
self.assertTrue(self.passed)

def post(self, extra=None):
headers = [('Content-Type', 'application/x-www-form-urlencoded')]
data = {'item1': json.dumps({"ref": "0123456789012345678901234"})}
Expand Down

0 comments on commit 2842077

Please sign in to comment.