albert
albert

Reputation: 8593

Python-Eve: Use Pre-Request Event Hooks to modify data before inserting to DB

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.

Upvotes: 4

Views: 3460

Answers (3)

Carlos Ríos
Carlos Ríos

Reputation: 31

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

Upvotes: 0

Gustavo
Gustavo

Reputation: 126

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.

Upvotes: 1

Nicola Iarocci
Nicola Iarocci

Reputation: 6576

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 +=).

Upvotes: 5

Related Questions