Photo by Markus Spiske on UnSplash

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).

Rejoice Mucheri
22 min readDec 1, 2023

--

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:

  1. AWS Account with Administrative privileges.
  2. AWS CLI configured with your AWS Access key and secret
  3. AWS SAM CLI
  4. Python.
  5. 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 terminalsam 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 called samconfig.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 WeatherApiwith 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 a POST 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 named WeatherTable).
    - 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-weatherendpoint in an API Gateway. The function is designed to insert weather data into a DynamoDB table, and a connector named addWeatherItemToDBis 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 to src.
  • Inside the src folder create a new file and name it create_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 and town values. The function parses the JSON payload from the incoming request to extract weather and town 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 500 statusCode 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 it update_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_NEWensures that the response includes the updated attributes. If the update is successful, it returns a success response with a 200 statusCode and the updated attributes.
    If an exception occurs like a DynamoDB update failure, it logs the exception, and returns an error response with a 500 statusCodeand 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 getWeatherItemToDBis 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 it get_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 it delete_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 it get_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 and JSON, add the following values to the request body and click SEND
{
"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 616as an id I will retrieve that. Make sure you go to your DynamoDB table and retrieve the id 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 and JSON, add the following values to the request body and click SEND
{
"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 the 752 id item.
  • While stick testing via Postman,n change the path to /weather/752 or the id 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.

--

--

Rejoice Mucheri

AWS Certified Solutions Architect-Associate. I love building on AWS and writing about it.