This blog post will demonstrate how to receive events from Azure Event Grid using a webhook from Zapier.
The sample code and hooks from this post can be found at https://github.com/dbarkol/event-grid-zapier.
The following image illustrates what we will be accomplishing in this post:
Background
Event Grid subscriptions can be handled by a growing collection of Azure services (such as Function, Logic Apps, Event Hubs and many more) as well as webhooks:
In the case of a webhook event subscription, the endpoint must prove that it can receive events by returning the validation code that is passed in from Event Grid during the registration process (see: WebHook Event Delivery).
Zapier is an integration service, similar to Logic Apps; that allows you to build workflows that can connect to a plethora of other services like Slack, MailChimp, Trello and many others.
Integration with Event Grid and other Azure services comes with first class support in regards to tooling and the validation/handshaking that occurs during the configuration of an event subscription.
Custom endpoints and 3rd party services, such as Zapier or endpoints hosted on other cloud provider, require you to support the validation step yourself.
Challenge – Returning the Validation Code with Zapier
The process of echoing back a validation code is straightforward for applications that you manage and have control over. The challenge with Zapier is that you don’t have as much control over the workflow and cannot respond back to the caller (trigger) that kicked off your application (the Event Grid topic).
To address this limitation, Event Grid now passes in another property called validationUrl that can be used to manually acknowledge the endpoint as a valid event subscription. This feature, currently in preview; will include an updated payload that is resembled below:
[{ "id": "2d1781af-3a4c-4d7c-bd0c-e34b19da4e66", "topic": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "subject": "", "data": { "validationCode": "512d38b6-c7b8-40c8-89fe-f46f9e9622b6", "validationUrl": "https://rp-eastus2.eventgrid.azure.net:553/eventsubscriptions/estest/validate?id=B2E34264-7D71-453A-B5FB-B62D0FDC85EE&t=2018-04-26T20:30:54.4538837Z&apiVersion=2018-05-01-preview&token=1BNqCxBBSSE9OnNSfZM4%2b5H9zDegKMY6uJ%2fO2DFRkwQ%3d" }, "eventType": "Microsoft.EventGrid.SubscriptionValidationEvent", "eventTime": "2018-01-25T22:12:19.4556811Z", "metadataVersion": "1", "dataVersion": "1" }]
The addition of the new field gives endpoints an alternative for acknowledging the request from Event Grid. All they need to do now is send a GET request to the address, which could be done manually through the browser or through other means with REST clients and libraries.
Goal: The goal for this post will be to automate this process within Zapier to avoid any manual steps.
Zapier Setup
When you create a new Zap, the first thing you must configure is a trigger. In this case, we will select Webhooks:
We then click on the show less common link to pick the Catch Raw Hook option:
The next step is where we will get the URL that will need to be copied for later use.
Once we have the Zap endpoint we then send it a sample request.
Important: We want this request to include all the details that we’ll use later within the Zap. That includes not only the body of the request but also any header values that we want to inspect and use. In regards to the body, it should include all the properties that we anticipate using later.
Our next step is to send a request to the webhook URL we just copied. I’ll use Postman since it’s a great tool for testing these scenarios. Here are the details of the request:
- POST to https://hooks.zapier.com/hooks/catch/{{your-webhook-details}}
- Header values
- Content-Type : application/json
- Aeg-Event-Type: SubscriptionValidation
- Body
-
[{ "id": "{{$guid}}", "topic": "subscription-details", "subject": "playlist", "data": { "validationCode": "{{$guid}}", "validationUrl": "some-url", "artist": "something goes here", "song": "song title" }, "eventType": "songadded", "eventTime": "2017-12-21T23:27:12.2422068Z" }]
-
Notice that the body includes not only the validation fields we anticipate for the initial request (validationCode and validationUrl), but also the fields we want to access when we receive future notifications (artist and song). These fields will vary by publishers. I’ve chosen artist and song to show how this will work end-to-end with a custom topic (more on that later).
After the request is sent we can view what was captured in the raw hook:
Now comes the integration step with Event Grid. We’ll add another action to the workflow – Code:
After selecting JavaScript for the coding option. We are able to add variables (or input values) from the previous step that we could leverage in our code.
We are interested in two values:
- The aeg-event-type value passed into the header – we will use this to determine if the request is a validation or notification message from Event Grid.
- The raw body of the request – this will let us inspect the original request body.
After adding these values, the input data option should look something like this:
The final piece on the Zapier side is the bit of code that will put this all together:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var obj = JSON.parse(inputData.rawBody); | |
if (inputData.eventType === 'SubscriptionValidation') { | |
fetch(obj[0].data.validationUrl) | |
.then(function(res) { | |
return res.text(); | |
}) | |
.then(function(body) { | |
var output = {eventType: inputData.eventType}; | |
callback(null, output); | |
}) | |
.catch(callback); | |
} else if (inputData.eventType === 'Notification'){ | |
var artist = obj[0].data.artist; | |
var song = obj[0].data.song; | |
var body = {"text": artist + " – " + song, "icon_emoji": ":musical_note:"}; | |
var slackUrl = "https://hooks.slack.com/services/{{slack-key}}"; | |
fetch(slackUrl, { | |
method: 'POST', | |
body: JSON.stringify(body), | |
headers:{'Content-Type':'application/json'} | |
}) | |
.then(function(res) { | |
return res.text(); | |
}) | |
.then(function(body) { | |
var output = {eventType: inputData.eventType}; | |
callback(null, output); | |
}) | |
.catch(callback); | |
} |
A breakdown of the code:
- Leveraging the input values from the previous steps, we can determine the type of event (line 3).
- We will use fetch to send a request to the validationUrl that we retrieved from the message body (lines 5-13). This will complete the validation process.
- Notification events will retrieve values from the request body and send a message to a slack channel (lines 15-35). This could be anything but we just wanted to show how you could parse values from the body.
Zapier note: I’m currently using the Free Plan on Zapier which limits the number of actions and options to use. Otherwise, we could put together a more meaningful Zap that leverages other services and actions.
Azure Setup
Let’s put together the necessary resources on Azure to see this working end-to-end. From the Cloud Shell in the Azure portal, add the preview extension for Event Grid:
az extension add –-name eventgrid
Initialize a few variables:
rgname=zapiertest-rg topicname=<unique-topic-name> zapierendpoint=<your-zapier-webhook-url>
Create a resource group:
az group create -l westus2 -n $rgname
Create a custom topic:
az eventgrid topic create -g $rgname --name $topicname -l westus2
Get the topic endpoint:
topicendpoint=$(az eventgrid topic show --name $topicname -g $rgname --query "endpoint" --output tsv)
Get the topic access key:
topickey=$(az eventgrid topic key list --name $topicname -g $rgname --query "key1" --output tsv)
Create the event subscription:
az eventgrid event-subscription create -g $rgname --topic-name $topicname --name zapier-sub --endpoint $zapierendpoint
Almost there, let’s copy a sample body:
body=$(eval echo "'$(curl https://raw.githubusercontent.com/dbarkol/event-grid-zapier/master/newsong.json)'")
And finally, make the request to the custom topic using curl:
curl -X POST -H "aeg-sas-key: $topickey" -d "$body" $topicendpoint
The end result looks like:
In summary, there are probably many different ways to accomplish this with Zapier. This seemed like a simple way to automate the validation process with Event Grid, which was our ultimate goal.
Reference
- Code and hooks: https://github.com/dbarkol/event-grid-zapier
- Zapier website: https://zapier.com
- Event Grid security: https://docs.microsoft.com/en-us/azure/event-grid/security-authentication