
Serverless Application on AWS
Serverless computing is a great way for application development. It eliminates the need to manage servers. The cloud providers even take care of scalability, monitoring, logging etc. This means as a developer you can completely focus on app development without worrying about the infrastructure and performance. And you will only be paying for the net usage of resources.
Let’s try to create a serverless application using AWS lambda, Dynamodb and API Gateway.
Components of application
Let’s try to create a serverless application using AWS lambda, Dynamodb and API Gateway.
- API Gateway: API gateway is the entrypoint of our serverless application. It will handle the incoming requests from the clients and gave the response from the backend service. We will use API Gateways to create Rest APIs. API Gateway can handle the task like authentication, authorization and traffic management and monitoring.
- Lambda funtion: Lambda function is small self contained units of code that run in response of events. They can be written in multiple languages like Python, Nodejs, Java and more. When an API Gateway receives a request, it can be configured to trigger a specific Lambda function. This function then processes the request, performs the necessary logic, and returns a response. The best thing about Lambda is that you only pay for the compute time used, making it highly cost-effective.
- DynamoDB: DynamoDB is a fully managed NoSQL database service that offers fast and predictable performance with seamless scaling. We’ll use DynamoDB to store the data that our API will manage. We’ll create tables, define data schemas, and perform CRUD (Create, Read, Update, Delete) operations using DynamoDB’s powerful API.
Lab
Step 1: Create IAM role
- Go to IAM from your AWS console.
- Choose the “Roles” option from the left sidebar.
- Create a role with the following properties.
- Trusted entity - Lambda
- Role name - lambda-apigateway-role
- Permissions - To allow lambda to read and write dynamodb and to write the cloud watch logs.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Statement1",
"Action": [
"dynamodb:DeleteItem",
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:UpdateItem"
],
"Effect": "Allow",
"Resource": "*"
},
{
"Sid": "Statement2",
"Resource": "*",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Effect": "Allow"
}
]
}
Step 2: Create Lambda function
- Click
Create function
in AWS Lambda Console - Select
Author from scratch
. Use name MyLambdaFunction , select Python 3.12 as Runtime. Under Permissions, selectUse an existing role
, and select lambda-apigateway-role that we created, from the drop down. - Click
Create function
- Replace the boilerplate coding with the following code snippet. Click on Deploy.
from __future__ import print_function
import boto3
import json
print('Loading function')
def lambda_handler(event, context):
'''Provide an event that contains the following keys:
- operation: one of the operations in the operations dict below
- tableName: required for operations that interact with DynamoDB
- payload: a parameter to pass to the operation being performed
'''
#print("Received event: " + json.dumps(event, indent=2))
operation = event['operation']
if 'tableName' in event:
dynamo = boto3.resource('dynamodb').Table(event['tableName'])
operations = {
'create': lambda x: dynamo.put_item(**x),
'read': lambda x: dynamo.get_item(**x),
'update': lambda x: dynamo.update_item(**x),
'delete': lambda x: dynamo.delete_item(**x),
'list': lambda x: dynamo.scan(**x),
'echo': lambda x: x,
'ping': lambda x: 'pong'
}
if operation in operations:
return operations[operation](event.get('payload'))
else:
raise ValueError('Unrecognized operation "{}"'.format(operation))
- To test the function you can create a new Test event with this payload.
{
"operation": "echo",
"payload": {
"somekey1": "somevalue1",
"somekey2": "somevalue2"
}
}
Click on “Test”.
Sample Output:
{
"somekey1": "somevalue1",
"somekey2": "somevalue2"
}
Step 3: Create DynamoDB
- Open the DynamoDB console.
- Choose Create table.
- Create a table with the following settings.
- Table name – lambda-apigateway
- Primary key – id (string)
- Choose Create.
Step 4: Create API Gateway
- Go to API Gateway console
- Scroll down and select
Build
for REST API - Give the API name as
Dynamo
, keep everything as is, clickCreate API
- By default, you will get the root path. But we will create one endpoint path.
- Input
dynamo
in the Resource Name, Resource Path will get populated. Click `Create Resource” - Let’s create a POST Method for our API. With the
/dynamo
resource selected, ClickActions
again and clickCreate Method
. - Select
POST
from drop down , then click checkmark - Select
Lambda Function
option for integration. Choose the lambda function that we have created earlier. ClickSave
.You should get the request-response workflow in the API Gateway page.
- Deploy the API
- Click on
Deploy API
button. - Select
New Stage
- Give
prod
as Stage Name. Now to invoke the API, go to the “Stages” from the left sidebar and get the endpoint for /dynamo path.
- Click on
Step 5: Test the application
- In Postman, you can use the URL from the API gateway and this payload to create some data in the dynamo db.
{
"operation": "create",
"tableName": "lambda-apigateway",
"payload": {
"Item": {
"id": "1",
"number": 12
}
}
}
- To get the stored items list, you can use this payload to get the list of items stored in the database.
{
"operation": "list",
"tableName": "lambda-apigateway",
"payload": {}
}
If these URLS gave you successfull response, then it means you application is working properly.
Congratulations on creating a serverless application from scratch. Now it’s your opportunity to modify the configuration and lambda function and expand your knowledge with serverless applications.
Feel free to watch our video for more detailed information. If you find the content useful, please subscribe to the channel.
Bonus
Here is the cloud formation template that can perform all the above steps at once.
AWSTemplateFormatVersion: '2010-09-09'
Description: Serverless application
Resources:
# Create IAM Role for Lambda
LambdaAPIGatewayRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: 'Allow'
Principal:
Service:
- 'lambda.amazonaws.com'
Action:
- 'sts:AssumeRole'
Policies:
- PolicyName: 'LambdaDynamoDBPolicy'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: 'Allow'
Action:
- 'logs:CreateLogGroup'
- 'logs:CreateLogStream'
- 'logs:PutLogEvents'
Resource: 'arn:aws:logs:*:*:*'
- Effect: 'Allow'
Action:
- 'dynamodb:*'
- 'dynamodb:DeleteItem'
- 'dynamodb:GetItem'
- 'dynamodb:PutItem'
- 'dynamodb:Query'
- 'dynamodb:Scan'
- 'dynamodb:UpdateItem'
Resource: '*'
# Create DynamoDB Table
DynamoDBTable:
Type: 'AWS::DynamoDB::Table'
Properties:
TableName: 'lambda-apigateway'
AttributeDefinitions:
- AttributeName: 'id'
AttributeType: 'S'
KeySchema:
- AttributeName: 'id'
KeyType: 'HASH'
ProvisionedThroughput:
ReadCapacityUnits: 5
WriteCapacityUnits: 5
# Create Lambda Function
MyLambdaFunction:
Type: 'AWS::Lambda::Function'
Properties:
FunctionName: 'MyLambdaFunction'
Handler: 'index.lambda_handler'
Runtime: 'python3.12'
Role: !GetAtt LambdaAPIGatewayRole.Arn
Code:
ZipFile: |
from __future__ import print_function
import boto3
import json
print('Loading function')
def lambda_handler(event, context):
'''Provide an event that contains the following keys:
- operation: one of the operations in the operations dict below
- tableName: required for operations that interact with DynamoDB
- payload: a parameter to pass to the operation being performed
'''
#print("Received event: " + json.dumps(event, indent=2))
operation = event['operation']
if 'tableName' in event:
dynamo = boto3.resource('dynamodb').Table(event['tableName'])
operations = {
'create': lambda x: dynamo.put_item(**x),
'read': lambda x: dynamo.get_item(**x),
'update': lambda x: dynamo.update_item(**x),
'delete': lambda x: dynamo.delete_item(**x),
'list': lambda x: dynamo.scan(**x),
'echo': lambda x: x,
'ping': lambda x: 'pong'
}
if operation in operations:
return operations[operation](event.get('payload'))
else:
raise ValueError('Unrecognized operation "{}"'.format(operation))
# Create API Gateway
MyApiGateway:
Type: 'AWS::ApiGateway::RestApi'
Properties:
Name: 'DynamoDBOperations'
# Create API Gateway Resource
ApiResource:
Type: 'AWS::ApiGateway::Resource'
Properties:
RestApiId: !Ref MyApiGateway
ParentId: !GetAtt MyApiGateway.RootResourceId
PathPart: 'dynamodbmanager'
# Create API Gateway Method
ApiMethod:
Type: 'AWS::ApiGateway::Method'
Properties:
MethodResponses:
- ResponseModels:
application/json: Empty
StatusCode: 200
ResourceId: !Ref ApiResource
RestApiId: !Ref MyApiGateway
HttpMethod: 'POST'
AuthorizationType: 'NONE'
Integration:
Type: 'AWS'
IntegrationHttpMethod: 'POST'
Uri:
Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyLambdaFunction.Arn}/invocations
IntegrationResponses:
- StatusCode: 200
# Deployment of API Gateway
ApiDeployment:
Type: 'AWS::ApiGateway::Deployment'
DependsOn: ApiMethod
Properties:
RestApiId: !Ref MyApiGateway
StageName: 'prod'
# Permission for API Gateway to invoke Lambda
LambdaApiGatewayInvokePermission:
Type: 'AWS::Lambda::Permission'
Properties:
FunctionName: !GetAtt MyLambdaFunction.Arn
Action: 'lambda:InvokeFunction'
Principal: 'apigateway.amazonaws.com'
SourceArn: !Sub 'arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${MyApiGateway}/*/*/dynamodbmanager'
Outputs:
ApiUrl:
Description: "URL for the API endpoint"
Value:
Fn::Sub:
- https://${MyApiGateway}.execute-api.${AWS::Region}.amazonaws.com/prod/dynamodbmanager
- MyApiGateway: !Ref MyApiGateway
Conclusion:
By leveraging serverless architecture, we eliminated the complexities of managing infrastructure, allowing us to focus solely on application logic. The pay-per-use model of AWS Lambda ensures cost-efficiency, making it an ideal choice for various applications.
Through hands-on experience, we gained insights into the power of combining these services to create a seamless and responsive application. Whether you’re a seasoned developer or just starting, understanding serverless computing and these AWS services is essential for building modern, cloud-native applications.
We encourage you to experiment further with AWS Lambda, DynamoDB, and API Gateway to unlock the full potential of serverless computing.
Important links