Intro to Webhooks and How to Receive them with Python

Posted by

This tutorial will be an introduction to the concept of webhooks. We will also build a simple Flask server that can receive GitHub webhooks. We will also see how to expose our local hosts.

What is a webhook?

Before talking about webhooks, let’s talk about APIs. Below is the data flow for an API.

API Data Flow

You make a GET/POST request to the API and you get a response back. If you want to learn more about working with APIs, check out my article on working with APIs with Python or my article on working with APIs with JavaScript.

Consider the Github API, what if we wanted to build an API that would send use an email every time a new issue is made in a repo. One way would be to build an API that would make a request every 1-2 minutes to check if a new issue is made and notify us. This process is known as polling. Basically, we would have to periodically make requests to check for a new issue. However, this seems inefficient. What if GitHub makes a request to our API whenever a new issue is created. This is known as a webhook. Instead of us making periodic requests, we just give GitHub our API’s endpoint and whenever a new issue is created, a request will be made to the endpoint we gave to Github. Webhooks are also known as Reverse APIs. Below is a comparison between polling and webhooks. This image was inspired by this article

Polling vs WebHooks

As you might have noticed, a lot of requests are made and depending on how frequently we make requests, there might be a slight delay between the new issue being created and our API getting notified.

Let’s create an API to receive a request whenever a new Issue is created in a Github repo.

Create a simple Flask Server

First, let’s create a hello world endpoint.

from flask import Flask,request,json

app = Flask(__name__)

@app.route('/')
def hello():
    return 'Webhooks with Python'

if __name__ == '__main__':
    app.run(debug=True)

Now we need to create an endpoint to receive the request from the GitHub API. This will be a standard endpoint that accepts POST requests.

@app.route('/githubIssue',methods=['POST'])
def githubIssue():
    data = request.json
    print(f'Issue {data["issue"]["title"]} {data["action"]}')
    print(f'{data["issue"]["body"]}')
    print(f'{data["issue"]["url"]}')
    return data

I read the docs and knew the keys for the JSON objects. You can use different keys to access more data like issue labels etc.

Now you can run your flask server

python3 __init__.py

Exposing our localhost URL publically

Webhooks require a public API endpoint since they can not make requests to endpoints such as ‘http://127.0.0.1:5000/’. One way would be to deploy the API and use the URL of the deployed API. Another way is to expose your localhost as a publically available URL. This will be temporary and will only work as long as your Flask server is running. Any request made to the public URL will also be made to your localhost URL.

We will use ngrok to expose our localhost URL. You will have to create an account.

Screen Shot 2021-10-26 at 1.41.52 AM.png
Download ngrok for your OS and unzip it. Now open a terminal and cd to the directory where the unzipped ngrok file is present. Type the following command in the terminal

ngrok  http <PORT NUMBER> 

Eg: If your flask server is running on port 5000, you’d have to type the following

ngrok http 5000

Screen Shot 2021-10-26 at 1.38.25 AM.png
You should see a similar output in your terminal. The public URL is the URL next to ‘Forwarding’. In my case it is http://35cc-69-58-102-156.ngrok.io. If you access your public URL, you should see the same thing you see when you access your localhost URL.

Creating an Issue Webhook

Chose any Github Repo you like. Go to Settings> Webhooks > Add Webhook
Screen Shot 2021-10-26 at 1.40.56 AM.png

Screen Shot 2021-10-26 at 1.43.52 AM.png

Enter your endpoint, in my case it is http://35cc-69-58-102-156.ngrok.io/githubIssue

Since we only want requests to be made when an Issue is created in the repo, select ‘Let me select individual events.’ and scroll down to choose ‘Issues’. Once you are down, scroll down and create the webhook.

Testing the Webhook

Create an Issue in your repo

Screen Shot 2021-10-26 at 1.47.09 AM.png

Now check the terminal where the flask server is running. I also added a label and closed the issue.

Screen Shot 2021-10-26 at 1.48.43 AM.png

Conclusion

Right now the Flask server doesn’t do much. However, you can build on top of it. Instead of just printing the data received, you can use the data and send a push notification or an email. I hope you found this article helpful. Connect with on LinkedIn , Twitter