Thursday, 21 May, 2020 UTC


Summary

Serverless applications are applications that are built, deployed, and then executed on-demand. The servers on which they run are provided by the cloud platform to which they are deployed, and the developer only needs to focus on writing the code.
The on-demand aspect ensures that the developer is only charged for execution time, as opposed to being charged for a fixed amount of bandwidth or a specific number of servers.
Bref is an open-sourced project that lets you create and deploy serverless applications, called functions, to AWS Lambda using PHP. It integrates with the Serverless Framework which abstracts the operations involved in deploying and monitoring such applications.
In this tutorial, you will be building a webhook for the Twilio Console Debugger that gets triggered when there is an error with (any of) your Twilio application(s) and send the payload to Slack.
Prerequisites
To follow along, you will need:
  • PHP 7.2 or later
  • An AWS account (AWS provides a free tier that you can use for testing this application).
  • A Twilio account
  • Composer and npm installed
  • A Slack Hook URL
  • Ngrok (for testing the webhook locally)
Install the AWS CLI and the Serverless Binary
The AWS CLI is a python utility that helps you manage your AWS services from the command line. Install it via pip if it’s not installed already. Notice the --upgrade flag to upgrade any of its requirements that might be already installed. To get started, run the following command in your terminal:
$ pip3 install awscli --upgrade 
Next, install the serverless binary and make it available as a system command with:
$ npm i -g serverless 
Create a Bref Project
Create a new directory for the project (I’m naming mine bref-twilio-errors) and enter into it with:
$ mkdir bref-twilio-errors && cd bref-twilio-errors 
Next, install the application dependencies with:
$ composer require bref/bref vlucas/phpdotenv maknz/slack 
The above command imports the bref CLI, phpdotenv to read environment variables from our .env file, as well as maknz/slack which provides direct access to the Slack API from our PHP code.
Initialize a bref project in the current directory with ./vendor/bin/bref init and select the HTTP application runtime to set up an HTTP endpoint. That way, your code will be able to process HTTP requests using the AWS API Gateway.
On initialization, bref creates two files:
  • serverless.yml: This acts as a configuration for the serverless framework. It includes information by the framework to provision and deploy your applications (a.k.a. functions) on the specified cloud provider (AWS in this case). index.php: This is the default entry point for your application.
Next, create the .env file to hold your app configuration and credentials:
$ touch .env 
Add your Slack hook URL as an environment variable as shown below:
SLACK_HOOK_URL="https://hooks.slack.com/services/XXXXXXXXXXXXXXXXX" 
Handle Incoming Errors
Open the handler file for your function specified in serverless.yml (for our case, it is index.php located in the project root directory file) and replace its content with the code block below:
<?php use Maknz\Slack\Client; require_once './vendor/autoload.php'; $dotenv = Dotenv\Dotenv::createImmutable(__DIR__); $dotenv->load(); 
The code above will import the Slack Client and make all the variables declared in the .env file available for your application.
Next, create the “sender” functions in the same index.php file. One function will be used to send the payload received from the Twilio Console Debugger to Slack and the other will be responsible for sending errors generated by this application.
function sendHandlerError($message) {  $slackHookUrl = getenv("SLACK_HOOK_URL");  $client = new Client($slackHookUrl);  $client->to('#general')->send($message); }  function sendTwilioError($message) {  $slackHookUrl = getenv("SLACK_HOOK_URL");  $client = new Client($slackHookUrl);  $client->to('#general')  ->enableMarkdown()  ->send($message); } 
To complete your index.php file, update it to parse the incoming request, trigger the appropriate message and send an “OK” response back as shown below:
try{  if (strtoupper($_SERVER['REQUEST_METHOD'] != 'POST')) {  throw new Exception("Received non-post request on webhook handler");  }   $params = json_decode($_POST['Payload']);   $message = "New Twilio error at ". $_POST['Timestamp'] ."\n";  $message .= "*Level:* ".$_POST['Level']."\n";  $message .= "*Console URL:* https://www.twilio.com/console/debugger/".$_POST['Sid']."\n";  $message .= "*Details: *\n";  $message .= "```\n";  $message .= json_encode($params->more_info, JSON_PRETTY_PRINT)."\n";  $message .= "```";  sendTwilioError($message); } catch (Exception $e) {  sendHandlerError($e->getMessage()); } header("Content-type: application/json"); echo json_encode(['message' => "OK"]); exit(0); 
Test it out Locally
To test your progress so far, start the PHP in-built server on port 8888 with php -S localhost:8888 and open an ngrok tunnel on the same port with ngrok http 8888.
Then copy out the generated ngrok Forwarding URL and set it as a webhook in your Debugger Console.

Trigger an Error

To send a request to your webhook, you will have to intentionally trigger an error. One way to do this is to create an invalid TwiML bin with the code below and link it with an active phone number:
<?xml version="1.0" encoding="UTF-8"?> <Response>  <Say><Message>Hello, world!</Say> </Response> 
NOTE: You will be prompted to confirm whether or not you want to save the TwiML Bin with invalid markup. Proceed to save.
Call the phone number that is hooked to the invalid TwiML bin and it should trigger an error on your Debugger page.
If successful, the details of the error are sent to the configured Slack channel - courtesy of the webhook.
Set up AWS Credentials
Your AWS resources need to be accessible to serverless for your deployments to be successful. To complete, get the AWS Key, Secret, and region of an IAM user that has the following permissions:
  • AWSLambdaFullAccess
  • IAMFullAccess
  • AmazonAPIGatewayAdministrator
  • AmazonSSMFullAccess
  • AWSCloudFormationFullAccess
Set up the user with a custom AWS profile locally with the command below:
$ serverless config credentials --provider aws --key AWS_KEY --secret AWS_SECRET --profile bref 
Also, add the Slack Hook URL to your AWS SSM parameter store with:
$ aws ssm put-parameter --region us-west-2 --profile bref --name '/bref-twilio-errors/slack-hook' --type String --value "YOUR_SLACK_HOOK_URL_HERE" 
That way, you can securely access the Hook URL as an environment variable without adding it to your code.
NOTE: Remember to change the value of the region flag to match your IAM user’s region.
Update your serverless config file to reflect these changes by modifying the provider section as shown:
provider:  name: aws  region: us-west-2 # your IAM user's AWS region  runtime: provided  profile: bref # the profile specified while running `serverless config credential...`  environment:  SLACK_HOOK_URL: ${ssm:/bref-twilio-errors/slack-hook} 
Deploy to AWS Lambda
In the project root directory, deploy the bref application with:
$ serverless deploy 
The command outputs your application URL (similar to https://XXXXXXX.execute-api.us-west-2.amazonaws.com/dev) in the endpoints section when it’s done. Update your Debugger webhook with the new URL and trigger your application error. If successful, a new message is sent to your configured Slack channel.
Conclusion
In this post, we explored the Bref serverless framework and how we can use it to see how our Twilio applications are performing in real-time. You can learn more about Bref from the docs. You can also learn more about the Serverless Framework here.
The complete source code for this tutorial is available on Github. Feel free to create a new issue if you run into a problem.
Michael Okoko is a software engineer and computer science student at Obafemi Awolowo University, Nigeria. He loves open source and is mostly interested in Linux, Golang, PHP, and fantasy novels! You can reach him via:
  • https://mchl.xyz
  • Github
  • Twitter