#Lambda + API Gateway Example
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)
##Architecture
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:
aws 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).
# swagger.yaml
# <<region>> : AWS region set in Pre-Requisites, referenced twice in swagger.yaml
# <<accountId>> : your global AWS account ID (found in MyAccount)
uri: arn:aws:apigateway:<<region>>:lambda:path/2015-03-31/functions/arn:aws:lambda:<<region>>:<<accountId>>:function:${stageVariables.LambdaFunctionName}/invocations
# template.yaml
CodeUri: s3://<bucket-name>/lambda_function.py.zip # name of S3 bucket created in Pre-Requiisites
DefinitionUri: s3://<bucket>/swagger.yaml # name of S3 bucket created in Pre-Requisites
Connect to a 64-bit Amazon Linux instance via SSH.
ssh -i key.pem ec2-user@public-ip-address
Ensure basic build requirements are installed.
sudo yum install python27-devel python27-pip gcc
Install native dependencies required by Pillow.
sudo yum install libjpeg-devel zlib-devel
Create and activate a virtual environment.
virtualenv ~/lambda-apigateway-twilio-tutorial
source ~/lambda-apigateway-twilio-tutorial/bin/activate
Install libraries in the virtual environment.
pip install Pillow
pip install boto3
pip install twilio
Install git.
sudo yum install git-all
Clone this repo and update lambda_function.py
.
# lambda_function.py
account_sid = "account_sid" # Twilio account SID
auth_token = "auth_token" # Twilio auth token
phone_number = "phone_number" # Twilio phone number
dynamodb = boto3.resource('dynamodb', '_region') # AWS region set in Pre-Requisites
table_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
aws cloudformation package \
--template-file template.yaml \
--output-template-file template-out.yaml \
--s3-bucket <your-s3-bucket-name>
aws cloudformation deploy \
--template-file <path-to-file/template-out.yaml \
--stack-name <STACK_NAME> \
--capabilities 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
./addphoto
, for example.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:
{
"body" : "$input.params('Body')",
"fromNumber" : "$input.params('From')",
"image" : "$input.params('MediaUrl0')",
"numMedia" : "$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](https://s3.amazonaws.com/smallya-useast-1/twilio-apig/integration_request.png)
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:
#set($inputRoot = $input.path('$'))
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Message>
<Body>
$inputRoot
</Body>
</Message>
</Response>
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
.First, let's test the Lambda function. Click the Actions dropdown and Configure test event. We need to simulate the JSON object passed by API Gateway. Example:
{
"body" : "hello",
"fromNumber" : "+19145554224" ,
"image" : "https://api.twilio.com/2010-04-01/Accounts/AC361180d5a1fc4530bdeefb7fbba22338/Messages/MM7ab00379ec67dd1391a2b13388dfd2c0/Media/ME7a70cb396964e377bab09ef6c09eda2a",
"numMedia" : "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.
##Troubleshooting
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)