How to handle WebHooks with Parse Server

Content List

Introduction

Have you ever wanted to integrate a 3rd Party Client with your SashiDo applications? I suppose you have, and there's an awesome feature called WebHooks which help you do just that. In simple terms, a WebHook allows any 3rd Party Client, that supports Webhooks, communicate and send information (Payload) to your Parse Server instance and vice-versa.

If you want to get more familiar on how to send WebHooks from your SashiDo application to 3rd Party services, check our article on How to set up WebHooks on SashiDo or watch out YouTube Video Tutorial.

Sending your own WebHooks is one thing, but let's say you want to Handle a WebHook sent from a 3rd Party Client, do something with the information, and respond back. Such WebHooks are also called Incoming WebHooks and the only thing you need to set up is a simple WebHook Handler.

Handling Incoming WebHooks

Handling an Incoming WebHook is a really easy task! An Incoming WebHook is just an HTTP GET or POST request that sends some information to your Parse Server.

As you may already know, every time you create an application with SashiDo, we automatically give you a Free Private GitHub Repository for it. In order for you to process the WebHook from your Parse Server, all you need to do is implement a Express route handler within your app.js file. That’s called Advanced Cloud Code and we’ve made an article about it. You can check the Useful Links section for a direct link to the article.

The app.js file is located in your application's GitHub Repository, in the cloud folder.

So let's get straight to the point!

Building your WebHook Handler

Let's first navigate to the app.js file. Navigate to Dashboard -> your app -> Core -> Cloud Code and click on the blue button Manage on GitHub in the upper right corner.

When you're in your repository, open the Cloud folder and you'll find the file app.js.

Now it's time to write the Express route handler.

   app.post('/webhookHandler', function(request, response) {
    console.info('Received!'); // Log every time a WebHook is handled.

    // Execute any logic that you want when the 3rd Party Client hits that endpoint

    response.status(200); // Let the sender know that we've received the WebHook
    response.send();
});

Afterwards, you can access the handler by adding /webhookHandler to the end of your Server URL. The Server URL is just the API URL Address without the /1/. You can find it in Dashboard -> Your App -> App Settings -> Security & Keys. It should look something like this https://pg-app-sd5ez1yjgta5vksvux7wdfjwiykcpt.scalabl.cloud/webhookHandler

Yes, it's that simple!

Let's break this down a bit. First, we define the app.post route handler with an endpoint /webhookHandler. You can name the endpoint whatever you want, but for the sake of simplicity, we call it like that.

After that, we can simply put console.info(‘Received!’) so we can track when we've received WebHooks through our Logs section in the Dashboard.

ProTip: It's good practice to handle the WebHook quickly, as most services require you to respond in a few seconds, otherwise, you'll get a Timeout error. If you just need to execute some custom logic of yours after receiving a WebHook, without responding to it, a simple response.status(200) and response.send() would do just fine to tell the service that you’ve received the WebHook. If you need to respond to the Webhook then you should always check the Docs of the 3rd Party Service so you know in what time interval you need to respond and in what format. Some services may have a responseURL attached with the Payload. You can use it if you need to send information back to the 3rd Party Service after some time.

You may also find the Express Docs useful so check them out too if you’d like. You can also check the Express Request/Response references.

That's about it. Now you can execute any logic that you want when you receive the WebHook! All good, but let's say you want to extract the payload and do something according to it.

Extracting information from the Request Body

Extracting information from the request is pretty easy too. We can use the Express Body Parser for that.

Include it at the beginning of your app.js file like this:

const bodyParser = require('body-parser');

app.use(
    bodyParser.urlencoded({
        extended: true
    })
);

app.use(bodyParser.json()); // If you are processing a JSON formatted Content-Type

After you define the Body Parser you can use it to convert the information to something readable and then use it in some way.

Most 3rd Party Services provide you with unique Verification Token. When they send you a WebHook, they also include the Verification Token in the payload. That way, you can make sure that the WebHook is coming from the desired 3rd Party Client by comparing your Verification Token with the one sent with the WebHook payload like this:

app.post('/webhookHandler', function(request, response) {
    var payload = JSON.parse(request.body.payload);
    if (payload.verificationToken !== 'your_verification_token') {
        response.status(403).end('Access forbidden');
    }
    ...
});

You should note that every 3rd Party Client may send different information and with Content-Type, so always be sure to check what payload is sent through the WebHook so you know exactly how to process the information.

If you want to learn more about the body parser, check out the body-parser npm package. It’s already installed so you don’t have to do it.

Here’s how your app.js file would look like if you followed the steps:

/*
 * Advanced Cloud Code Example
 */
const express = require('express');
const app = express();
const bodyParser = require('body-parser');

app.use(
    bodyParser.urlencoded({
        extended: true
    })
);

app.post('/webhookHandler', function(request, response) {
    var payload = JSON.parse(request.body.payload);
    if (payload.verificationToken !== 'your_verification_token') {
        response.status(403).end('Access forbidden');
    } else {
        response.status(200);
        response.send();
    }
});

/*
 * Exporting of module.exports.app is required.
 * we mount it automatically to the Parse Server Deployment.
 */

module.exports = app;

Example WebHook Handler with Slack

It's time to put everything from above into a good example, in this case, with Slack.

As you may already know, Slack is one of the most used chat platforms by developers. But did you know that you can integrate it with your SashiDo application? For example, let us say that you want to have a Slash Command that will list all unbilled users of your application and another Slash Command which will try to bill them. Well, the good news is that this can be done pretty easily using Slack apps and WebHooks!

1. Setting up your SashiDo app

  1. Navigate to Dashboard -> Your App -> Core -> Browser -> User Class.
  2. Create a new column of type boolean and name it billed.
  3. If you don't have any entries in the User class, add some users and set the billed field of some of them to false
    • Easiest and fastest way to add new entries in your User class is to go to Dashboard -> Your App -> Core -> API Console.
    • For Request Type choose POST, be sure to check the Use MasterKey toggle to be true.
    • Set the endpoint to classes/_User.
    • In Query Parameters type {"username":"someUsername","password":"somePassword","billed": false} and hit Send Query.

2. Cloud Code

For this example, we’ve implement 2 Slash Commands:

  • /unbilled - Will retreive all unbilled users.
  • /bill - Tries to bill all the unbilled users.

For each of the two, we’ve created a separate WebHook handler which we've included in a separate file. We've provided a direct link to it at the end of this section.

Now let’s see how the handler for the /bill command works. First, we define the route handler with an endpoint of /billUser.

app.post('/billUser', async (req, res) => {});

After that, we execute our custom logic to try and bill our users:

app.post('/billUser', async (req, res) => {
    // Find all unbilled users
    const unbilled = await new Parse.Query(Parse.User)
        .equalTo('billed', false)
        .find();

    // Iterate through all the user objects
    for (let user of unbilled) {
        await user.save({ billed: true }, { useMasterKey: true });
    }

    // When it's done, we send back a response to Slack
    res.send({ text: `${unbilled.length} users successfully billed!` });
});

For the sake of simplicity, we've modified the code so it's short and readable. If you want to check the full code, which includes error handling and the /unbilled Slash Command Handler, you can check the app.js file in our Demo app.js Example Code file. If you want you can even copy-paste the code in your app.js file.

3. Setting up Slack

  1. Go to Slack and create your own Workspace.
  2. After that, create a new Slack App. Name it whatever you want and select the Workspace in which you want to implement it.
  3. Navigate to Slash Commands in the section Add features and functionality and click on Create New Command.
    • For Command, type /unbilled (this is the name of your Slash Command).
    • In Request URL type your ServerURL + the route we defined in the app.js file. You can find your SashiDo App's ServerURL in Dashboard -> Your App -> App Settings -> Security & Keys -> API URL Address. Just replace the /1/ at the end with /getUnbilledUsers. It shoud look something like this - "https://pg-app-sd5ez1yjgta5vksvux7wdfjwiykcpt.scalabl.cloud/getUnbilledUsers".
    • Add a short description to the command and optionally a hint, then click on Save.
    • Repeat for the /bill Slash Command. Just replace the Request URL endpoint to /billUser (that's our second route handler in the app.js file).

4. Let’s test it out!

So, we've implemented 2 Slash Commands - /unbilled, which will return all of our unbilled users, and /bill which will try to bill all unbilled users.

Let us try it out and see what happens!

First of all, we can see that we have a few unbilled users in the picture below:

Let's head to our Slack Workspace and try out our newly implemented Slash Commands.

We can even check our Logs section in Dashboard -> your app -> Core -> Logs to see if the process went well internally. In our case, everything was fine, as we can see in the picture below:

We've also implemented logic to handle scenarios should there be no unbilled users. If you execute any of the above Slash Commands in this case, you'll get the following response:

That's about it. As I said before, pretty simple, right?

Other use cases and scenarios

By now you've learned how to handle WebHooks. Let's look at some use cases.

Approving Comments/Uploads

Let's say that you have an application in which your users can comment and upload pictures. You would probably want to regulate which comments and pictures are uploaded in some way.

One neat example is an integration with Slack and your SashiDo application with WebHooks. It would work in a way that when a person uploads or makes a comment, a WebHook will be fired to Slack, notifying you and your team and letting you choose whether the comment or picture is appropriate or not. After you've made your choice, another WebHook will be fired, this time to your SashiDo App. After handling it with your custom logic, the picture/comment will be posted or not, and you can send a message to the person if the content is not appropriate.

If you want to read more about Slack's WebHooks, Interactive messages & Buttons check out the following links:

Billing service

Say you want to have a paid plan for your SashiDo application. You can imagine how hard it would be to write your own custom billing service and so on. That can be easily avoided by integrating a 3rd Party Billing Service like Chargebee for example, with your SashiDo app using WebHooks.

If you're interested and want to learn more about it, check out Chargebee's Events & WebHooks

Chat/Ticketing

Have you ever want to get feedback from your users, handle problems and issues that they might have, but don't want to write such features from scratch? With WebHooks you can do just that. For example, you can use 3rd Party Chat/Ticketing Services like Intercom or Teamwork and integrate them with your SashiDo apps using WebHooks.

If you're interested in such integration, you can check out both Teamwork and Intercom's Documentation about WebHooks.

SMS & Calling

Depending on what your application's about, you can choose to have SMS & Calling through it. That, by itself, would be a very laborious task if you choose to code it yourself. With WebHooks, you can use a service like Twillio to send text messages and make calls from your application.

If you're interested in SMS & Calls integration for your application, you can check our blog post GitHub integration of Advanced Cloud Code part 1 or Twillio's Documentation

Final

Whoa! That was a lot to take in. The great part is that you can use this information to your advantage and integrate your SashiDo apps with some other cool services!

Happy coding!