Build an email sending API with background processing using AWS SNS
Being a scripting ninja, DevOps king, a puppet expert or a Kubernetes GDE is all good and has its place. However, sometimes you want to quickly get an app running without having to think of a server, a container orchestrator, or infrastructure provisioning.
Enter serverless.
A way to build and run applications and services without having to manage infrastructure. AWS
By the end of this tutorial, we’ll have done the following:
- Describe a serverless architecture
- Delve into Chalice, a Python serverless framework
- Build an email sending serverless app using SNS for background processing
- Deploy to Amazon Web Services (AWS) Lambda
Note: This is not an article on architecture or what is the best way to skin this cat; rather a quick dive into serverless. Maybe I will use SQS instead of SNS and write one function with both the API and trigger processor
Prerequisites
- Python
Since this is a python framework, I will assume that you, my reader have installed python and set up a virtual environment. Then do pip install chalice
to get ready for the next step or quickly do so:
$ python3.7 -m venv venv
$ source env/bin/activate
(venv)$ pip install chalice
AWS Chalice allows you to quickly(really quickly) create and deploy applications that use Amazon API Gateway and AWS Lambda. It can be used to:
- Create rest APIs
- Periodic tasks
- Respond to triggers from AWS resources like SQS, S3 and others e.g. invoke this function whenever a message is uploaded to ‘myqueue’
Before we begin, you will need to have an AWS account. If you do, then you should proceed to create an AWS IAM role that Chalice will use to autogenerate all the resources it needs while deploying your app.
Chalice expects to pick the AWS credentials from ~/.aws/config so once you’ve created the IAM role, add the access key and secret in that file.
If the file doesn't already exist, create it
mkdir ~/.aws
touch ~/.aws/config
Then add the contents of the config file
[default]
aws_access_key_id = YOUR_ACCESS_KEY_HERE
aws_secret_access_key = YOUR_SECRET_ACCESS_KEY
region = YOUR_REGION
So then we are ready to proceed.
3. AWS SNS (Amazon Simple Notification Service)
Fully managed pub/sub messaging for microservices, distributed systems, and serverless applications
4. AWS Lambda
Project Structure
Our project will consist of two apps:
- An API written in chalice to receive POST requests for new emails and logging them in an AWS SNS topic.
- A python lambda function for listening to the SNS topic trigger and processing all logged emails.
Build the API
Now that we have chalice installed, let’s create a new app
(env)$ chalice new-project
Build and run the app locally
(env)$ chalice local
Serving on 127.0.0.1:8000
Using curl
, we can test the API
curl -X GET http://localhost:8000/
{"hello": "world"}
Good. since we’ve seen how the basic app runs, let’s proceed to add a function along with a route in the app.py
to create emails and add them to an SNS topic.
import json
import boto3@app.route('/emails', methods=['POST'])
def create_email():
email_as_json = app.current_request.json_body
sns = boto3.client('sns')
result = sns.publish(
TopicArn=os.environ.get('SNS_TOPIC'),
Subject=email_as_json['subject'],
Message=json.dumps(email_as_json)) return {'status': 200,'msg': 'Message queued'}
Then run the app locally and test with a request
$ curl -H "Content-Type: application/json" -X POST -d '{"sender": "sender@mail.com","receiver":"yourmail@gmail.com","subject":"test","message":"serverless with lambda and chalice"}' http://localhost:8000/emails/
Deploy the API
Using the deploy
command, we can simply use Chalice to deploy and create a Lambda function that can be accessible via a REST API.
(env)$ chalice deploy
Creating deployment package.
Creating IAM role: mailer-dev
Creating lambda function: mailer-dev
Creating Rest API
Resources deployed:
- Lambda ARN: arn:aws:lambda:us-west-2:995516939866:function:mailer-dev
- Rest API URL: https://pcscihtza3.execute-api.us-west-2.amazonaws.com/api/
Note: The generated ARN and API URL in the above snippet will vary from user to user.
If you try to POST a request on https://pcscihtza3.execute-api.us-west-2.amazonaws.com/api/emails, it will fail with 500 Internal Server Error
since we have not yet added the SNS topic. So let’s proceed to create a one using the AWS console.
When the form is brought up, add a topic name and create it, copy the ARN of the topic
Replace the SNS_TOPIC
word in the code with the ARN which is a unique identifier of the topic on all of AWS
TopicArn='arn:aws:sns:us-east-1:90551693986:testapp',
Note: Your ARN will be different from the one above but will be in the format
arn:
partition
:service
:region
:account-id
:resource
After adding the topic name, make a POST request again and it should be successful this time.