Name: lambda-apigateway-twilio-tutorial
Owner: Amazon Web Services - Labs
Owner: AWS Samples
Description: Getting started with AWS Lambda + Amazon API Gateway. Use Twilio MMS to upload photos to S3 without servers.
Created: 2015-12-14 19:57:43.0
Updated: 2018-01-12 01:14:46.0
Pushed: 2017-05-29 20:25:07.0
Homepage: null
Size: 534
Language: Python
GitHub Committers
User | Most Recent Commit | # Commits |
---|
Other Committers
User | Most Recent Commit | # Commits |
---|
This example uses Twilio to save an image from your mobile phone to the AWS cloud. A user sends an image using MMS to a Twilio phone number which sends a request to an Amazon API Gateway endpoint that triggers a Lambda function. The app then returns a publicly accessible link to the image in AWS S3. This app uses AWS Lambda, API Gateway, DynamoDB & S3. It is also 100% serverless!
NOTE: The project has been updated to use AWS Serverless Application Model (AWS SAM)
Step-by-step on how to configure, develop & deploy this app on AWS.
us-east-1
, us-west-2
& eu-west-1
.fromNumber
for primary key of type String. We don't need any additional indexes and you can keep the read/write capacity at 1 for this example.In the AWS Region you plan to deploy, make sure you have an existing Amazon S3 bucket in which SAM can create the deployment artifacts.
Else create a new bucket using the following AWS CLI command:
s3 mb s3://<your-bucket-name>
Before deploying the project to SAM for the first time, you'll need to update some variables in lambda_function.py
and template.yaml
/swagger.yaml
(found in sam/
folder).
agger.yaml
region>> : AWS region set in Pre-Requisites, referenced twice in swagger.yaml
accountId>> : your global AWS account ID (found in MyAccount)
arn:aws:apigateway:<<region>>:lambda:path/2015-03-31/functions/arn:aws:lambda:<<region>>:<<accountId>>:function:${stageVariables.LambdaFunctionName}/invocations
mplate.yaml
Uri: s3://<bucket-name>/lambda_function.py.zip # name of S3 bucket created in Pre-Requiisites
nitionUri: s3://<bucket>/swagger.yaml # name of S3 bucket created in Pre-Requisites
Connect to a 64-bit Amazon Linux instance via SSH.
-i key.pem ec2-user@public-ip-address
Ensure basic build requirements are installed.
yum install python27-devel python27-pip gcc
Install native dependencies required by Pillow.
yum install libjpeg-devel zlib-devel
Create and activate a virtual environment.
ualenv ~/lambda-apigateway-twilio-tutorial
ce ~/lambda-apigateway-twilio-tutorial/bin/activate
Install libraries in the virtual environment.
install Pillow
install boto3
install twilio
Install git.
yum install git-all
Clone this repo and update lambda_function.py
.
mbda_function.py
unt_sid = "account_sid" # Twilio account SID
_token = "auth_token" # Twilio auth token
e_number = "phone_number" # Twilio phone number
modb = boto3.resource('dynamodb', '_region') # AWS region set in Pre-Requisites
e_users = dynamodb.Table('table_name') # name of DyanmoDB created in Pre-Requisites
Run bash ./create_lambda_package.sh
which will create the lambda_function.zip
.
Download the .zip
file using a command like scp -i key.pem ec2-user@public_ip_address:/path/to/file .
where /path/to/file
can be determined by readlink -f lambda_function.zip
.
Upload both swagger.yaml
and lambda_function.zip
into the S3 bucket.
To deploy the project for the first time with SAM, and for each subsequent code update, run both of the following AWS CLI commands in order.
You can use the basic_lambda_function.py as the reference for a simple backend to test the end to end flow
cloudformation package \
mplate-file template.yaml \
tput-template-file template-out.yaml \
-bucket <your-s3-bucket-name>
cloudformation deploy \
mplate-file <path-to-file/template-out.yaml \
ack-name <STACK_NAME> \
pabilities CAPABILITY_IAM
After executing the cloudformation deployment, you'll need to navigate to IAM > Roles > STACK_NAME-LambdaFunctionRole-UNIQUE_STRING and attach the AmazonS3FullAccess
and AmazonDynamoDBFullAccess
policies to enable the Lambda function with sufficient permissions.
This section has been retained for users who want to refer to the blog post or want to manually create the API Gateway and Lambda resources
lambda_function.py
. Read through the module and provide a few variables: Twilio credentials, DynamoDB table name & region and S3 ingest bucket. We will upload as a .zip because our function requires a few external libraries, such as Twilio Python SDK. Compress httplib2, pytz, twilio & lambda_function.py and upload as a .zip file.main_function.lambda_handler
would call the method def lambda_handler()
inside main_function.py
. Let's call it lambda_function.lambda_handler
to match lambda_function.py
.Create a new API. Give it a name and description. This will be our RESTful endpoint.
Create a resource. The path should be /addphoto
, for example.
We need to add a method to this resource. Create a GET method with Lambda integration and select the function we created earlier. API Gateway isn't able to process POST requests that are URL encoded, so we are using GET as a workaround.
Now let's setup the Integration Request. Twilio's GET request will be of type application-x-www-form-urlencoded
. This Integration step will map this type to a JSON object, which Lambda requires. In the Integration Requests page create a mapping template. Content-type is application/json
and template:
y" : "$input.params('Body')",
mNumber" : "$input.params('From')",
ge" : "$input.params('MediaUrl0')",
Media" : "$input.params('NumMedia')"
More on Intergration Requests.
$input.params()
parse the request object for the corresponding variable and allows the mapping template to build a JSON object.
Screenshot
Let's ensure the response is correct. Twilio requires valid XML. Change the response model for 200 to Content-type: application/xml
. Leave models empty.
Lambda cannot return proper XML, so API Gateway needs to build this. This is done in Integration response as another mapping template. This time we want to create Content-type: application/xml and template:
($inputRoot = $input.path('$'))
l version="1.0" encoding="UTF-8"?>
ponse>
<Message>
<Body>
$inputRoot
</Body>
</Message>
sponse>
Our Lambda function solely returns a string of the SMS body. Here we build the XML object and use $inputRoot
as the string.
https://xxxx.execute-api.us-west-2.amazonaws.com/prod/addphoto
MESSAGING_SERVICE_NAME
.
y" : "hello",
mNumber" : "+19145554224" ,
ge" : "https://api.twilio.com/2010-04-01/Accounts/AC361180d5a1fc4530bdeefb7fbba22338/Messages/MM7ab00379ec67dd1391a2b13388dfd2c0/Media/ME7a70cb396964e377bab09ef6c09eda2a",
Media" : "1"
Click Test. At the bottom of the page you view Execution result and the log output in Cloudwatch logs. This is very helpful for debugging.Please Note: Twilio is a 3rd party service that has terms of use that the user is solely responsible for complying with (https://www.twilio.com/legal/tos)