This content originally appeared on Twilio Blog and was authored by Dotun Jolaoso
In this tutorial, we’ll explore how to receive Twilio webhooks using DigitalOcean Functions, enabling you to build powerful and flexible applications that interact with Twilio. Twilio webhooks provide a seamless way to receive real-time notifications from Twilio. By leveraging DigitalOcean Functions, a serverless computing platform, you can handle Twilio webhooks and perform custom actions based on the received data. For example, you can trigger a CI/CD workflow, such as Github Actions, whenever your Twilio number receives an SMS message.
Technical requirements
To follow along, you’ll need the following:
- A free Twilio account.
- A Python Development Environment running Python 3.9+. You need to have the virtualenv package running locally as well.
- A DigitalOcean account. You should also have doctl, which is DigitalOcean’s command line interface tool, installed and running locally. You can read more about setting it up here.
Creating a DO Function
To get started with creating a DO Function, you will be making use of the doctl
command line tool. However, you first need to install support for serverless functions. You can do that by running the following command:
$ doctl serverless install
This will install and download the serverless extension. Once that is completed, you are now ready to initialize a new function project using a helper command that the doctl
tool provides.
To work with DigitalOcean Functions via the command line using doctl
, you need to connect doctl
to a Functions namespace. Namespaces are used to isolate and organize functions and their settings. If this is your first time working with DO Functions, you’ll need to create a namespace before you can connect it and start deploying Functions. You can do this by running the following command:
doctl serverless namespaces create --label example-namespace --region nyc1
The --label
flag is used to specify the name of the namespace while the --region
flag indicates which region the namespace should be in. You can learn more about creating namespaces here.
After doing that, you can now connect to the namespace by running the command below:
$ doctl serverless connect
You can now create functions and deploy them to your namespace.
Next, from the directory where you want your project to reside, run the following to initialize a sample function project.
$ doctl serverless init --language python twilio
This will create a twilio project directory that contains a project.yml configuration file, a packages directory containing the sample package, a hello function directory, and the sample “Hello world” function code.
Here’s an outline of what the current directory structure looks like:
twilio/
├── packages
│ └── sample
│ └── hello
│ └── hello.py
└── project.yml
This is good for a start, however, you’ll need to rename some of the directories and files to align with the purpose of the function.
- Rename the
sample
package totwilio
- Rename the
hello
function directory towebhooks
- Rename the
hello.py
file to__main__.py
. This is in accordance with what DigitalOcean recommends where the file containing the handler function to be executed is named__main__.py
.You can read more about it here
Here’s an outline of what the new directory structure is supposed to look like:
twilio/
├── packages
│ └── twilio
│ └── webhooks
│ └── __main__.py
└── project.yml
Next, replace the project.yml
file at the root of the project’s directory with the following:
targetNamespace: ''
parameters: {}
packages:
- name: twilio
environment:
TWILIO_AUTH_TOKEN: ${TWILIO_AUTH_TOKEN},
TWILIO_WEBHOOK_URL: ${TWILIO_WEBHOOK_URL}
parameters: {}
annotations: {}
actions:
- name: webhooks
runtime: 'python:default'
web: raw
The packages and actions names are now consistent with the naming used for the directories. You’ve also added the environment variables the function needs to run. The environment variables will be fetched from a .env file you’ll be creating shortly using Templating.
Add the following code to the __main__.py file:
import os
from http import HTTPStatus
from urllib.parse import parse_qs
from twilio.request_validator import RequestValidator
def main(args, context):
body = args.get("http").get("body", {})
data = parse_qs(body, True)
data = {k: v[0] for k, v in data.items()} # convert values to strings
validator = RequestValidator(os.getenv('TWILIO_AUTH_TOKEN'))
url = os.getenv('TWILIO_WEBHOOK_URL')
header = args.get("http").get("headers").get("x-twilio-signature", "")
if not validator.validate(url, data, header):
return {
"statusCode": HTTPStatus.BAD_REQUEST,
"body": "invalid signature"
}
return {
"statusCode": HTTPStatus.ACCEPTED,
"body": body
}
The first argument args
to the main()
function is typically an HTTP request event or web event that contains information about the request. The second parameter context
contains information about the function’s execution environment.
Within the main()
function, the request body is fetched from the args
dictionary using args.get(“http”).get(“body”)
. If the body
key is not found, it assigns an empty dictionary to the body
variable. If it is found, the returned value is a string. The parse_qs
function is then used to parse the body
into a dictionary.
To verify the request is authentic, you can use the RequestValidator
class included in the Twilio Helper library for Python. This class is initialized by passing in your Twilio Auth Token.
The validate()
method on the class is called passing in the webhook URL, which is obtained as an environment variable using os.getenv
, a dictionary with the request body, and the signature contained in the X-Twilio-Signature
header. If this method returns False
, the request is aborted with a status code of 400.
Deploying a DO Function
Functions with external dependencies require a build script and a requirements.txt file before they can be deployed. You can read more about why they are required here. Within the packages/twilio/webhooks directory, create a requirements.txt and build.sh file.
Note: Depending on the OS you’re currently running, you might need to give the right permissions to the build.sh file. On Mac/Linux, you can do that by running the command:
chmod +x packages/twilio/webhooks/build.sh
Add the twilio
library as a dependency to the requirements.txt file:
twilio==8.2.0
The build.sh script is used to create a virtualenv
and install the packages. Paste the following in the file:
#!/bin/bash
set -e
virtualenv --without-pip virtualenv
pip install -r requirements.txt --target virtualenv/lib/python3.9/site-packages
Environment Variables
Before you can deploy the function to DigitalOcean, you need to configure your environment variables. Head over to your Twilio Console, and take note of your Auth Token.
Head back to the root of the project’s directory and create a .env file. Edit the file with the following credentials:
TWILIO_AUTH_TOKEN=xxxx
TWILIO_WEBHOOK_URL=xxxx
Replace the TWILIO_AUTH_TOKEN
with the actual value you noted from your Twilio Console.
For the TWILIO_WEBHOOK_URL
field, you can use a random string as the value there temporarily. You’ll be updating that field shortly after the function has been deployed.
Next, cd
out of the project directory and run the command below to deploy the function:
doctl serverless deploy twilio
Once the function has been successfully deployed, you can now fetch the URL where the function was deployed by running the command below:
doctl sbx fn get twilio/webhooks --url
The command outputs the URL details:
https://faas-fra1-afec6ce7.doserverless.co/api/v1/web/fn-2932edc9-6e03-47ae-bd94-10f89c11a51f/twilio/webhooks
You can now head back to the project’s directory, and update the TWILIO_WEBHOOK_URL
field in the .env file with the actual URL. Next, cd
out of the project and then redeploy the project by running the deploy
command:
doctl serverless deploy twilio
Once you have deployed the function, you can get the function URL by running the following command:
doctl sls fn get twilio/webhooks --url
You can now take the function URL and configure your Twilio account with it. You can learn more about doing that here.
Conclusion
In this tutorial, you’ve seen how to get started with DigitalOcean Functions and deploy a serverless function you can use for processing incoming webhooks from Twilio. You’ve also seen how convenient it is to deploy the function by running a command. This tutorial can serve as the foundation for building more complex serverless functions with DigitalOcean and Twilio.
Dotun is a backend software engineer who enjoys building awesome tools and products. He also enjoys technical writing in his spare time. Some of his favorite programming languages and frameworks include Go, PHP, Laravel, NestJS, and Node.
Website: https://dotunj.dev/
GitHub: https://github.com/Dotunj
Twitter: https://twitter.com/Dotunj_
This content originally appeared on Twilio Blog and was authored by Dotun Jolaoso
![](https://www.radiofree.org/wp-content/plugins/print-app/icon.jpg)
Dotun Jolaoso | Sciencx (2023-05-17T19:55:56+00:00) Receiving Twilio Webhooks Using DigitalOcean Functions. Retrieved from https://www.scien.cx/2023/05/17/receiving-twilio-webhooks-using-digitalocean-functions/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.