Build a Serverless REST API with AWS SAM
A beginner’s guide on how to build your first serverless CRUD REST API (every code detail explained).
Table of Contents
∘ Introduction
∘ What is Serverless?
∘ What are REST APIs?
∘ Prerequsites
∘ Services
∘ AWS Serverless Application Model (SAM)
∘ AWS Lambda
∘ Amazon API Gateway
∘ Amazon DynamoDB
∘ Task 1: Project Setup
∘ Explore the SAM template.
∘ Task 2: Create a Weather table
∘ Task 3: Create a Weather API
∘ Task 4a: Create a CreateWeather Endpoint.
∘ Task 4b: Create a CreateWeather Lambda Function.
∘ Task 5a: Create an UpdateWeather Endpoint.
∘ Task 5b: Create an UpdateWeather Lambda Function.
∘ Task 6a: Create a GetWeather Endpoint.
∘ Task 6b: Create a GetWeather Lambda Function.
∘ Task 7a: Create a DeleteWeather Endpoint.
∘ Task 7b: Create a DeleteWeather Lambda Function.
∘ Task 8a: Create a ListWeather Endpoint.
∘ Task 8b: Create a ListWeather Lambda Function.
∘ Final Project Code: Github Repository
∘ Deploy and Testing
∘ Testing the CRUD Endpoints
∘ Conclusion
Introduction
Ever wondered what exactly is this serverless everyone keeps talking about and what is a REST API? Well not to worry I got you covered.
In this project I will walk you through how to build a serverless REST API. The application you will build is a weather application that will perfom (CRUD) create, read, update and delete operations. You will learn the workings of different serverless services and how to configure them, so let’s get into it. Project Credit: EduCloud Academy.
What is Serverless?
Serverless is a cloud-native development model that allows developers to build and run applications without having to manage servers.
There are still servers in serverless, but they are abstracted away from app development. A cloud provider handles the routine work of provisioning, maintaining, and scaling the server infrastructure. Developers can simply package their code and deploy on AWS or any other cloud service provider of their choice.
What are REST APIs?
An API i.e. (Application Programming Interface), serves as a set of guidelines that outline how various applications or devices can establish connections and exchange information with each other, more like communicate with each other.
When an API follows the design principles of the REST, i.e. (Representational State Transfer) architectural style, it is referred to as a REST API. Due to its adherence to these principles, REST APIs are commonly called RESTful APIs. REST API architectural style for an uses HTTP requests to access and use data. That data can be used to GET, PUT, POST and DELETE data types, which refers to the reading, updating, creating and deleting of operations concerning resources.
Prerequsites
Before you can proceed with this project, you will need to have the below prerequisites installed and configured:
- AWS Account with Administrative privileges.
- AWS CLI configured with your AWS Access key and secret
- AWS SAM CLI
- Python.
- Postman. Postman is an application used for API testing. It is an HTTP client that tests HTTP requests, utilizing a graphical user interface, through which we obtain different types of responses that need to be subsequently validated.
Services
AWS Serverless Application Model (SAM)
The AWS Serverless Application Model (AWS SAM) is a toolkit that improves the developer experience of building and running serverless applications on AWS.
AWS Lambda
AWS Lambda is a serverless, event-driven compute service that lets you run code for virtually any type of application or backend service without provisioning or managing servers.
Amazon API Gateway
Amazon API Gateway is a fully managed service that makes it easy for developers to create, publish, maintain, monitor, and secure APIs at any scale
Amazon DynamoDB
Amazon DynamoDB is a fully managed, serverless, key-value NoSQL database designed to run high-performance applications at any scale. DynamoDB offers built-in security, continuous backups, automated multi-Region replication, in-memory caching, and data import and export tools.
Task 1: Project Setup
Now that you have gotten an overview of the project you will be building and the services being used, let’s start building.
- You will first initialise a SAM application by running the following command in your terminal
sam init
.
Follow the prompts and make the following selections as shown in the steps below to initialise you application.
- From the Which template source would you like to use option? Choose: 1
- From the Choose an AWS Quick Start application template option. Choose: 1
- For the Use the most popular runtme and package type? (python and zip) [y/N]: Select: y
- Select (Yes), y for the rest of the prompts as shown in the image below.
- For the Project name [sam app] option type the name you would like to use for your project and press enter. For mine , I choose riri-weather-rest-api.
You should have an output like the one shown below.
You should have a project structure like the one below.
riri-weather-rest-api
├── events
├── events.json
├── hello_world
├── _init_.py
├── app.py
├── requirements.txt
├── tests
├── __init__.py
├── .gitignore
├── README.md
├── samconfig.toml
└── template.yaml
Now that you have initialised your project its time to build and deploy your application, make sure you open the project folder in the IDE of your choice, I used VSCode.
- Open a new terminal in your IDE and run the following commands.
sam build
sam deploy --guided
Code Explanation
The sam build
command prepares an application for subsequent steps in the developer workflow, such as local testing or deploying to the AWS Cloud.
When you run the sam build
command the SAM CLI first checks and installs the necessary software and libraries mentioned in the requirements.txt
file located in your hello_world
project directory.
- Follow the prompts as shown in the image below to deploy your application.
Code Explanation
The sam deploy --guided
command will package your application into a deployment package. This package contains all the code, dependencies, and configurations needed to run your application. The deployment package is saved in the .aws-sam/build
folder.
The sam deploy --guided
command will package and deploy your application to AWS, with a series of prompts:
- Stack Name: You need to provide a unique name for your deployment stack to use in AWS CloudFormation. I suggest you use a name matching your project name.
- AWS Region: Specify the AWS region where you want your application to be deployed.
- Confirm changes before deploy: You can choose whether you want to manually review any changes that will be made during deployment. If set to “yes,” you’ll get a chance to review any changes; if set to “no,” changes will be deployed automatically.
- Allow SAM CLI IAM role creation: Many serverless applications require AWS Identity and Access Management (IAM) roles for Lambda functions to access AWS services securely. If set to yes, this prompt allows the SAM CLI to create these roles with minimum required permissions.
- Save arguments to
samconfig.toml
: You can opt to save your deployment settings in a configuration file calledsamconfig.toml
file within your project. This allows you to easily redeploy your application in the future without re-entering all the parameters.
- For the Deploy this changeset? [y/N] option. Choose: y
Once the changeset has been deployed you will find your API Gateway Endpoint URL in the output values displayed after deployment.
You can go ahead and copy and paste the API Gateway Endpoint URL in your browser. You should get a response as shown in the image below.
Explore the SAM template.
Now that you have successfully deployed a Hello World API, you can explore the template.yaml
file. An AWS SAM template file closely follows the format of an AWS CloudFormation template file. If you would like to learn more about AWS Sam template take a look at these articles by Alan Blockley: AWS SAM Demystified and Demystifying the Basic Anatomy of an AWS SAM Template.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
riri-weather-rest-api
Sample SAM Template for riri-weather-rest-api
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 3
MemorySize: 128
Tracing: Active
Api:
TracingEnabled: true
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: hello_world/
Handler: app.lambda_handler
Runtime: python3.9
Architectures:
- x86_64
Events:
HelloWorld:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /hello
Method: get
ApplicationResourceGroup:
Type: AWS::ResourceGroups::Group
Properties:
Name:
Fn::Sub: ApplicationInsights-SAM-${AWS::StackName}
ResourceQuery:
Type: CLOUDFORMATION_STACK_1_0
ApplicationInsightsMonitoring:
Type: AWS::ApplicationInsights::Application
Properties:
ResourceGroupName:
Ref: ApplicationResourceGroup
AutoConfigurationEnabled: 'true'
Outputs:
# ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
# Find out more about other implicit resources you can reference within SAM
# https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
HelloWorldApi:
Description: API Gateway endpoint URL for Prod stage for Hello World function
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
HelloWorldFunction:
Description: Hello World Lambda Function ARN
Value: !GetAtt HelloWorldFunction.Arn
HelloWorldFunctionIamRole:
Description: Implicit IAM Role created for Hello World function
Value: !GetAtt HelloWorldFunctionRole.Arn
Task 2: Create a Weather table
Inorder for you to get the application to perform all the CRUD operations we want it to do, there is going to be a need for a database element. This is where you are going to store all the weather details. For this you will create a DynamoDB table.
Remember you are building a serverless API so forget the AWS console.
At this point you have an understanding of the anatomy of a SAM template. If you don’t understand the anatomy of a SAM template check out the previous section of this article Explore the SAM template .
- Open the template.yaml file, under the Resources section add the following code:
Resources:
WeatherTable:
Type: AWS::DynamoDB::Table
Properties:
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 5
WriteCapacityUnits: 5
Code Explanation
The code above defines a DynamoDB table named “WeatherTable” with a primary key consisting of a single attribute named “id” with a type of “S” (String). The table is provisioned with a read capacity of 5 RCUs and a write capacity of 5 WCUs.
You want to make your DynamoDB table name accesible to the other resources being used by your application,so you will have to add it to our Globals sections.
- Under the Globals section, add the following code:
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Runtime: python3.10
CodeUri: src/
Timeout: 3
MemorySize: 128
Environment:
Variables:
TABLE_NAME: !Ref WeatherTable
Code Explanation
The above code defines the global settings for AWS Lambda functions. These settings include the runtime, timeout, and memory size of the functions. It also sets a global environment variable TABLE_NAME
to dynamically reference the name of a DynamoDB table WeatherTable
in the template. These global settings provide a convenient way to maintain consistency across multiple Lambda functions within your serverless application.
Task 3: Create a Weather API
Now you will create an API resource which adds methods that can be invoked through HTTPS endpoints via API Gateway.
- Still in your template.yaml file, under the Resources section, add the following code:
WeatherApi:
Type: AWS::Serverless::Api
Properties:
StageName: dev
Description: serverless api for weather application
Code Explanation
The code above defines an API Gateway named WeatherApi
with specific properties. The API has a stage named dev
, and it is described as a “serverless api for weather application.” The API Gateway is serving as the entry point for the serverless application, handling incoming requests and routing them to the appropriate serverless functions.
Your template should look something like the code below now.
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
rest_weather_api
Sample SAM Template for rest_weather_api
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Runtime: python3.10
CodeUri: src/
Timeout: 3
MemorySize: 128
Environment:
Variables:
TABLE_NAME: !Ref WeatherTable
Resources:
WeatherApi:
Type: AWS::Serverless::Api
Properties:
StageName: dev
Description: serverless api for weather application
WeatherTable:
Type: AWS::DynamoDB::Table
Properties:
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
ProvisionedThroughput:
ReadCapacityUnits: 5
WriteCapacityUnits: 5
Outputs:
# ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
# Find out more about other implicit resources you can reference within SAM
# https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
WeatherApi:
Description: "API Gateway endpoint URL for dev stage for create weather function"
Value: !Sub "https://${WeatherApi}.execute-api.${AWS::Region}.amazonaws.com/dev/"
Task 4a: Create a CreateWeather Endpoint.
You have created your API Gateway weather API resource, you will need to create and configure the different endpoints for your API. In this task you create the first one, a CreateWeather endpoint.
- In your
template.yaml
file you will create the endpoint under the Resources section, go to your template and add the following code:
CreateWeather:
Type: AWS::Serverless::Function
Description: 'Lambda function inserts weather data into DynamoDB table'
Properties:
FunctionName: CreateWeatherLambda
Handler: create_weather.lambda_handler
Events:
ApiEvent:
Type: Api
Properties:
Path: /create-weather
Method: POST
RestApiId: !Ref WeatherApi
Connectors:
addWeatherItemToDB:
Properties:
Destination:
Id: WeatherTable
Permissions:
- Write
Code Explanation
In the code above you specify CreateWeather
as the identifier for the serverless function and the following parameters are defined.
Function Definition:
- Type: Specifies the AWS resource type as a serverless function.
- Description: Provides a brief description of the function’s purpose.
Function Properties
- FunctionName: Sets the name of the Lambda function to “CreateWeatherLambda.”
- Handler: Specifies the code entry point, pointing to the lambda_handler function in the create_weather module ( you will be creating this shortly).
- Events: Configures the events that trigger the Lambda function. In this case, it’s triggered by an API event.
API Event:
- Type: Specifies the event type as an API event.
- Properties: Configures properties related to the API event.
- Path: Defines the endpoint path/create-weather
.
- Method: Specifies the HTTP method that triggers the Lambda function. In this case aPOST
request.
- RestApiId: References the WeatherApi resource using!Ref
to get the API Gateway ID.
Connectors:
- addWeatherItemToDB: Defines a connector named
addWeatherItemToDB.
- Properties: Configures properties for the connector.
- Destination: Identifies the destination of the connector (in this case, the DynamoDB table namedWeatherTable
).
- Permissions: Specifies the permissions required for the connector, allowing write access.
In summary the code sets up a serverless function triggered by a POST request to the /create-weather
endpoint in an API Gateway. The function is designed to insert weather data into a DynamoDB table, and a connector named addWeatherItemToDB
is established to facilitate this data insertion.
Task 4b: Create a CreateWeather Lambda Function.
Now that you have your create-weather
resource created you want to be able to save or add weather details into your DynamoDB table. Remember in the last task you made configurations for a lambda function that is designed to insert data into a DynamoDB table when a POST
request is made.
In this next part you are going to create that lambda function.
- From your project source code folder, change the
hello-world
folder name tosrc
. - Inside the
src
folder create a new file and name itcreate_weather.py
- Open the
create_weather.py
file you just created and add the following code:
import json
import os
import random
import boto3
dynamodb = boto3.resource('dynamodb')
table_name = os.environ.get("TABLE_NAME")
table = dynamodb.Table(table_name)
def lambda_handler(event, context):
print(f"event is {event}")
print(f"table name is {table_name}")
weather = json.loads(event['body'])['weather']
town = json.loads(event['body'])['town']
id = str(random.randrange(100, 999))
item = {
'id': id,
'weather': weather,
'town': town
}
try:
table.put_item(Item=item)
return {
'statusCode': 200,
'body': json.dumps({"message":"Weather successfully created!"})
}
except Exception as e:
return {
'statusCode': 500,
'body': json.dumps({"message":str(e)})
}
Code Explanation
Let’s break down the code above to get a full understanding of what is happening.
Imports
- The first thing that your function will do is import a few libraries, the main import being
boto3
this is the official AWS SDK for Python. The other libraries are more straightforward,json
library for working with JSON data,os
module for interacting with the operating system,random
module for generating random numbers.
AWS Resource Setup
- The next part of the code you get the DynamoDB resource using the boto3 library. Next it retrieves the DynamoDB table name from the environment variables you defined in the Globals section of your
template.yaml
file and connects it to the to the DynamoDB table.
Lambda Function Handler
- The
lambda_handler
function is the entry point for the Lambda function. It logs the incoming event (request data) and the DynamoDB table name.
Processing Request Data
- Your lambda function expects the event body to have
weather
andtown
values. The function parses the JSON payload from the incoming request to extractweather
andtown
values. It then generates a random ID for the DynamoDB item and creates a DynamoDB item using the extracted data.
DynamoDB Insertion and Exception Handling
- The final part of the code tries to insert the created item into the DynamoDB table using the
put_item
method. If there is an exception, like a DynamoDB write failure, it catches the exception and returns an error response with a 500statusCode
and a JSON message containing the exception details.
In summary, the function is designed to handle events triggered by the API Gateway POST
request to /create-weather
. It extracts weather and town data from the request, generates a random ID, creates a DynamoDB item, and attempts to insert it into the specified DynamoDB table. The function provides a success response if the insertion is successful and an error response if there is an exception during the process.
Task 5a: Create an UpdateWeather Endpoint.
The UpdateWeather
endpoint you are creating will update an existing weather item. Navigate to the Resources section of your template.yaml
file and add the following code to create the UpdateWeather
endpoint.
UpdateWeather:
Type: AWS::Serverless::Function
Description: 'Lambda function updates weather item in DynamoDB table'
Properties:
FunctionName: UpdateWeatherLambda
Handler: update_weather.lambda_handler
Events:
ApiEvent:
Type: Api
Properties:
Path: /weather/{id}
Method: PUT
RestApiId: !Ref WeatherApi
Connectors:
updateWeatherItemToDB:
Properties:
Destination:
Id: WeatherTable
Permissions:
- Write
Code Explanation
Notice that this code is almost similar to the earlier code we saw in Task 4a. the only difference besides the function name and handler, is that your Path
and Method
are different. In this case, when a PUT
request is made to the endpoint at path /weather/{id}
, this lambda function would be invoked.
The UpdateWeather
endpoint you just created will update an existing weather item that is triggered by a PUT
request to the /weather/{id}
endpoint in the API Gateway. The function is designed to update weather-related data in a DynamoDB table, and a connector named updateWeatherItemToDB
is established to facilitate this data update.
Task 5b: Create an UpdateWeather Lambda Function.
Like in Task 4b, you made configurations for a lambda function. In this next part you are going to create an UpdateWeather
lambda function.
- Inside the
src
folder create a new file and name itupdate_weather.py
- Open the
update_weather.py
file you just created and add the following code:
import json
import os
import boto3
dynamodb = boto3.resource('dynamodb')
table_name = os.environ.get("TABLE_NAME")
table = dynamodb.Table(table_name)
def lambda_handler(event, context):
weather = json.loads(event['body'])['weather']
town = json.loads(event['body'])['town']
print(f"event {event}")
print(f"pathParameters {event['pathParameters']}")
print(f"weather {weather}")
print(f"town {town}")
weather_id = event['pathParameters']['id']
print(f"weather_id {weather_id}")
try:
response = table.update_item(
Key={
'id': weather_id
},
UpdateExpression="set #weather = :weather, #town = :town",
ExpressionAttributeNames={
"#weather": "weather",
"#town": "town"
},
ExpressionAttributeValues={
":weather": weather,
":town": town
},
ReturnValues="UPDATED_NEW"
)
return {
'statusCode': 200,
'body': json.dumps(response['Attributes'])
}
except Exception as e:
print(e)
return {
'statusCode': 500,
'body': json.dumps({'message': 'Something went wrong'})
}
Code Explanation
Like the CreateWeather
lambda function you created in Task 4b, the UpdateWeather
function code basically does the same thing. Let’s break down a few key differences.
DynamoDB Update and Response
- The function will try to update an item in the DynamoDB table using the
update_item
method. It updates the weather and town attributes based on the received values. - The
ReturnValues=UPDATED_NEW
ensures that the response includes the updated attributes. If the update is successful, it returns a success response with a 200statusCode
and the updated attributes.
If an exception occurs like a DynamoDB update failure, it logs the exception, and returns an error response with a 500statusCode
and a JSON message.
Task 6a: Create a GetWeather Endpoint.
I am sure by now you have an idea of the main tasks for this project. You are basically creating an endpoint and a lambda function for each of the CRUD operations. You have so far created an endpoint and lambda function for both the create
and update
operations for our API. Now you will create the same for the read
operation.
As in the previous tasks, you will navigate to the Resources section of your template.yaml
file and add the following code to create the GetWeather
endpoint first.
GetWeather:
Type: AWS::Serverless::Function
Description: 'Lambda function gets weather item in DynamoDB table'
Properties:
FunctionName: GetWeatherLambda
Handler: get_weather.lambda_handler
Events:
ApiEvent:
Type: Api
Properties:
Path: /weather/{id}
Method: GET
RestApiId: !Ref WeatherApi
Connectors:
getWeatherItemToDB:
Properties:
Destination:
Id: WeatherTable
Permissions:
- Read
Code Explanation
The code above sets up a serverless function named GetWeather
that is triggered by a GET
request to the /weather/{id}
endpoint. The function is designed to retrieve weather-related data from the DynamoDB table, and a connector named getWeatherItemToDB
is established with read permissions to facilitate this data retrieval.
Task 6b: Create a GetWeather Lambda Function.
In this next part you are going to create an GetWeather
lambda function, like you have done in some of the previous tasks.
- Inside the
src
folder create a new file and name itget_weather.py
- Open the
get_weather.py
file you just created and add the following code:
import json
import os
import boto3
dynamodb = boto3.resource('dynamodb')
table_name = os.environ.get("TABLE_NAME")
table = dynamodb.Table(table_name)
def lambda_handler(event, context):
weather_id = event['pathParameters']['id']
try:
response = table.get_item(Key={'id': weather_id})
return {
'statusCode': 200,
'body': json.dumps(response['Item'])
}
except table_name:
return {
'statusCode': 500,
'body': json.dumps('Error getting weather')
}
Code Explanation
The code above is for a Lambda function that is designed to handle events triggered by a GET
request to /weather/{id}
. It retrieves weather-related data from a DynamoDB table based on the provided id
and provides a success or error response accordingly. The DynamoDB retrieval logic is encapsulated within a try-except block to handle any potential exceptions that might occur during the operation.
Task 7a: Create a DeleteWeather Endpoint.
With the create
, read
and update
endpoints and lambda functions created and configured, you are now going to create and configure the delete
operation.
Navigate to the Resources section of your template.yaml
file and add the following code to create the DeleteWeather
endpoint.
DeleteWeather:
Type: AWS::Serverless::Function
Description: 'Lambda function deletes weather item from DynamoDB table'
Properties:
FunctionName: DeleteWeatherLambda
Handler: delete_weather.lambda_handler
Events:
ApiEvent:
Type: Api
Properties:
Path: /weather/{id}
Method: DELETE
RestApiId: !Ref WeatherApi
Connectors:
deleteWeatherItemToDB:
Properties:
Destination:
Id: WeatherTable
Permissions:
- Write
Code Explanation
The code above sets up a serverless function named DeleteWeather
. The function will be triggered by a DELETE
request to the /weather/{id} endpoint.
The function is designed to delete a weather-related item from a DynamoDB table, and a connector named deleteWeatherItemToDB
is established with write permissions to facilitate this data deletion.
Task 7b: Create a DeleteWeather Lambda Function.
You have now created your delete endpoint, now you configure the delete
operation by creating a lambda function.
- Inside the
src
folder create a new file and name itdelete_weather.py
- Open the
delete_weather.py
file you just created and add the following code:
import json
import os
import boto3
dynamodb = boto3.resource('dynamodb')
table_name = os.environ.get("TABLE_NAME")
table = dynamodb.Table(table_name)
def lambda_handler(event, context):
weather_id = event['pathParameters']['id']
print(f"weather id {weather_id} is being deleted")
try:
table.delete_item(Key={
"id": weather_id
})
return {
'statusCode': 200,
'body': json.dumps({"message": "Weather item deleted successfully"})
}
except table_name:
return {
'statusCode': 500,
'body': json.dumps({"message": "Weather item not deleted successfully"})
}
Code Explanation
The above code is for a Lambda function is designed to handle events triggered by the API Gateway DELETE
request to /weather/{id]
. It deletes a weather-related item from a DynamoDB table based on the provided id
and provides a success or error response accordingly. The DynamoDB deletion logic is encapsulated within a try-except block to handle any potential exceptions that might occur during the operation.
Task 8a: Create a ListWeather Endpoint.
At this point you have created and configured all the endpoints and functions for your CRUD operations for your API. It would be nice if you can retrieve of all the items you have created from your table, so you are going to create and configure the final endpoint and function. Let’s call this, the GetAllWeather
endpoint.
From the Resources section of your template.yaml
file and add the following code to create the GetAllWeather
endpoint.
GetAllWeather:
Type: AWS::Serverless::Function
Description: 'Lambda function gets all weather item in DynamoDB table'
Properties:
FunctionName: GetsAllWeatherLambda
Handler: get_weathers.lambda_handler
Events:
ApiEvent:
Type: Api
Properties:
Path: /weathers
Method: GET
RestApiId: !Ref WeatherApi
Connectors:
getsWeatherItemToDB:
Properties:
Destination:
Id: WeatherTable
Permissions:
- Read
Code Explanation
Basically code above sets up a serverless function named GetAllWeather
that is triggered by a GET
request to the /weathers
endpoint in an API Gateway. The function is designed to retrieve all weather-related items from a DynamoDB table, and a connector named getsWeatherItemToDB
is established with read permissions to facilitate this data retrieval.
Task 8b: Create a ListWeather Lambda Function.
- Inside the
src
folder create a new file and name itget_weathers.py
- Open the
get_weathers.py
file you just created and add the following code:
import json
import os
import boto3
dynamodb = boto3.resource('dynamodb')
table_name = os.environ.get("TABLE_NAME")
table = dynamodb.Table(table_name)
def lambda_handler(event, context):
try:
response = table.scan(TableName=table_name)
return {
'statusCode': 200,
'body': json.dumps(response['Items'])
}
except table_name:
return {
'statusCode': 500,
'message': json.dumps({"message": "Unable to get weather"})
}
Code Explanation
You will notice that this function has one significant difference to the others, that is the DynamoDB Scan Operation. here it uses the scan
method to retrieve all items from the DynamoDB table and the result is stored in the response
variable.
Your last function is designed to handle events triggered by the API Gateway GET
request to /weathers
. It scans the DynamoDB table to retrieve all weather-related items and provides a success or error response accordingly. The DynamoDB scan operation and exception handling logic are encapsulated within a try-except block to handle any potential exceptions that might occur during the operation. The retrieved items are then returned in the response body.
Final Project Code: Github Repository
Those were quite some tasks you accomplished. Congratulations for coming this far. You have created all the endpoints and functions required to make your weather API perfom CRUD operations. if you have come this far it means you are now ready to deploy your API. You can confirm all your code before deploying against the source code here.
Deploy and Testing
You are almost at the final stage of the project, and Congratulations once again for coming this far. Inorder for you to test your API, you will need to deploy it first.
- Open your terminal or IDE and run the following commands
sam build
sam deploy --guided
- Follow the Prompts as shown below, making sure you type in the correct name of your API and the correct region you are deploying your API too.
- Once your API is finished to deploy, you should get an endpoint URL in the outputs block as shown below.
Testing the CRUD Endpoints
Your API is now deployed, It’s time to test all the endpoints you just spend some time creating and configuring.
- From your DynamoDB console notice that you do not any items created in the table.
Testing the Create Weather Endpoint
First, you will test the Create Weather Endpoint. You are going to copy the API Gateway endpoint URL you got in the outputs sections after deploying your API.
- Open Postman and paste the endpoint URL in the
POST
request header. - The create weather path is
/create-weather
. Add this to your endpoint URL. - Your request body formatters should be set to
raw
andJSON
, add the following values to the request body and clickSEND
{
"weather": "Cold",
"town": "Johannesburg"
}
- You should have something that looks like the image below.
You should have a “Weather successfully created” response. At this point navigate back to your DynamoDB console to your table, an item should have been created in your table.
- Click the
SEND
option a few more time to create more than one item.
Testing the Get Weather Endpoint
You have confirmed that an item or 2 where created in your DynamoDB table. Let’s proceed to the next test, to retrieve an item you created from the DynamoDB table.
- From Postman, you are going to change the path to match an
id
of an item you created in your DynamoDB table. - In my case I created an item with
616
as anid
I will retrieve that. Make sure you go to your DynamoDB table and retrieve theid
of an item you created. - You will make a
GET
request using the/weather/id
as shown in the image below - You will not need to fill any information in the request body.
Testing the Update Weather Endpoint
Ok, so you have managed to create and retrieve an item from your DynamoDB table. You are going to update that item. In my case I am working with item 616
.
- From your Postman dashboard you are going to change the path to
/weather/616
- You will make a
PUT
request. - Your request body formatters should be set to
raw
andJSON
, add the following values to the request body and clickSEND
{
"weather": "Cold",
"town": "Pretoria"
}
- You should have an output that looks like the image below.
Testing the Delete Weather Endpoint
You have created, retrieved and updated a weather item. Now let’s test the delete operation for your endpoint.
To test this you are going to delete any one of the items you created earlier.
- Pick any
id
of an item from the ones you created. In my case i chose the752
id
item. - While stick testing via Postman,n change the
path
to/weather/752
or theid
of an item you created in your DynamoDB. - You will make a
DELETE
request as shown in the image below:
Testing the List Weathers Endpoint
You have tested all the CRUD operations for your API, But I think as a final thing lets test your endpoint that lists and retrieves all the items you created in your table.
- From your Postman dashboard change the
path
to/weathers
- You will make a
GET
request. - You will not need to fill any information in the request body.
- A list of created weather items should be returned in JSON format as shown below;
Conclusion
You have come to the end of the project where you have learnt how to create a serverless CRUD API. You tested all the endpoints and made sure they where working. You also learnt about the AWS SAM template and its anatomy and learnt how to develop an API using Infrastructure as Code (IaC) tools, among other things.
Thank you for taking the time to read my article. Until next time, Keep building in the clouds as we turn the saying “Building castles in the air”, into a reality.
Rejoice Mucheri is a Cloud Engineer/Solutions Architect who is passionate about building solutions on AWS. A couple of years ago she made the courageous decision to move into tech and cloud computing from a Sales and Customer Success space. Now she leverages her decade plus experience working in client facing roles to build well architected solutions in the cloud. Follow her journey on LinkedIn and Medium.