4

I am adding new data into my Database by doing a POST-request on my eve-API. Since there need to be added some data from the Python side I thought I could add these data by using a pre-request event hook.

So is there a way to modify the data contained in the POST-request using a pre-request hook before inserting the data into the database? I already understood how to implement such a hook but do not have any clue about how to modify data before inserting to DB.

albert
  • 8,027
  • 10
  • 48
  • 84

3 Answers3

5

You probably want to look at database hooks, specifically at insert hooks:

When a POST requests hits the API and new items are about to be stored in the database, these vents are fired:

on_insert for every resource endpoint.

on_insert_<resource_name> for the specific resource endpoint.

Callback functions could hook into these events to arbitrarily add new fields or edit existing ones.

In the code below:

def before_insert(resource_name, documents):
    if resource_name == 'myresource':
        for document in documents:
            document['field'] = 'value'

app = Eve()
app.on_insert += before_insert

app.run()

Every time a POST hits the API the before_insert function is invoked. The function updates field1 for every document. Since this callback is invoked before the payload is sent to the database, changes will be persisted to the database.

An interesting alternative would be:

def before_insert(resource_name, documents):
    for document in documents:
        document['field'] = 'value'

app = Eve()
app.on_insert_myresource += before_insert

app.run()

In the callback we are not testing the endpoint name anymore. This is because we hooked our callback to the on_insert_myresoure event so the function will only be called when POST request are performed on the myresource endpoint. Better separation of concerns, code is simpler and also, improved performance since the callback is not going to be hit an all API inserts. Side note, eventually you can hook multiple callbacks to the same event (hence the use of the addition operator +=).

sush
  • 5,897
  • 5
  • 30
  • 39
Nicola Iarocci
  • 6,606
  • 1
  • 20
  • 33
  • It looks like this hook is invoked after the validation progress. So is there a way to combine this with the validation since required fields are still raising `required_field` errors? – albert Dec 11 '15 at 14:22
  • If the fields are required and they are missing validation kicks in and document is rejected. The hook fire before insertion and after validation. Can't you simply make the fields not-required? Or, you could customise the validator to process the `required` rule differently or, better, add support for a different rule (look at "Custom Validation" in the docs). – Nicola Iarocci Dec 11 '15 at 17:29
  • DB hooks on_fetch_item does not work with WSGI. When I run the server with ```python server.py``` Hooks work but when run the app with WSGI hooks dont work and no errors show in console. – haytham Mar 10 '20 at 07:27
1

In my case I wanted to duplicate documents if a given property is in data.

I have to use pre_POST event hook to do that.

def pre_notifications(request):
    data = json.loads(request.get_data())
    if 'payload' in data and 'condition' in data:
        notification = data['payload']
        documents = []
        users = app.data.pymongo().db.users.find()
        for user in users:
            copy_notification = copy(notification)
            copy_notification['user_email'] = user['user_email']
            documents.append(copy_notification)
        request._cached_data = json.dumps(documents).encode('utf-8')

First, I tried to replace request.data but it does not work. Doing some search on code I figured out the _cached_data property. Then it works.

Gustavo
  • 126
  • 1
  • 7
0

Just to complement the answer of @Gustavo (I cannot leave a comment in his answer). You can update the request._cached_json property without serializing your data.

Using his example:

def pre_notifications(request):
    data = json.loads(request.get_data())
    if 'payload' in data and 'condition' in data:
        notification = data['payload']
        documents = []
        users = app.data.pymongo().db.users.find()
        for user in users:
            copy_notification = copy(notification)
            copy_notification['user_email'] = user['user_email']
            documents.append(copy_notification)
        request._cached_json = documents
Carlos Ríos
  • 31
  • 1
  • 6