Use Serverless Functions
Introduction
You can use serverless functions along with Event Triggers to design an async business workflow without having to manage any dedicated infrastructure.
As Hasura Event Triggers can deliver database events to any webhook, serverless functions can be perfect candidates for their handlers.
Why use serverless functions?
- Cost effectiveness.
- No infra management.
- Async business logic.
Examples
You can find a bunch of examples for various serverless cloud providers in this repo:
https://github.com/hasura/graphql-engine/tree/master/community/boilerplates/event-triggers.
For example: update related data on a database event
In this example we make a note taking app. Whenever a user updates their note, we want to store a revision of that note in a separate table.
You can find the complete example at:
Let's consider the following simplified schema for the above:
notes (
id INT PRIMARY KEY,
note TEXT
)
note_revision (
id INT PRIMARY KEY,
note TEXT,
note_id INT FOREIGN KEY REFERENCES notes(id),
update_at TIMESTAMP DEFAULT now()
)
Whenever an update happens to the notes
table, we want to insert a row
into the note_revision
table.
For this we set up an Event Trigger on UPDATE
to the
notes
table which calls an AWS Lambda function. The AWS Lambda
function itself uses a GraphQL mutation to insert a new row into the
note_revision
table. As the Event Trigger payload in case of updates gives us both the old and the new data, we can store
the old note data in our revision table.
Our AWS Lambda code looks like this:
// Lambda which gets triggered on insert, and in turns performs a mutation
const fetch = require('node-fetch');
const adminSecret = process.env.ADMIN_SECRET;
const hgeEndpoint = process.env.HGE_ENDPOINT;
const query = `
mutation updateNoteRevision ($noteId: Int!, $data: String!) {
insert_note_revision (objects: [
{
note_id: $noteId,
note: $data
}
]) {
affected_rows
}
}
`;
exports.handler = (event, context, callback) => {
let request;
try {
request = JSON.parse(event.body);
} catch (e) {
return callback(null, { statusCode: 400, body: 'cannot parse hasura event' });
}
const response = {
statusCode: 200,
body: 'success',
};
const qv = { noteId: request.event.data.old.id, data: request.event.data.old.note };
fetch(hgeEndpoint + '/v1/graphql', {
method: 'POST',
body: JSON.stringify({ query: query, variables: qv }),
headers: { 'Content-Type': 'application/json', 'x-hasura-admin-secret': adminSecret },
})
.then(res => res.json())
.then(json => {
console.log(json);
callback(null, response);
});
};