Building Modern Serverless API's with AWS: DynamoDB, Lambda, and API Gateway(Part 4)
Building a serverless API with SAM.
I love creating and writing about the creation of software.
Search for a command to run...
Building a serverless API with SAM.
I love creating and writing about the creation of software.
No comments yet. Be the first to comment.
A Technical / Non Technical overview of the dynamoDb for Beginners
Building a serverless API with SAM.
Watch the complete Video on Youtube https://www.youtube.com/watch?v=kKX-8L_R2XM Prerequisites Before proceeding make sure you have these dependencies Docker Python 3.11 and above AWS CLI Full access to a foundation model. For this workshop, we'll...

Introduction In a previous workshop, Building event-driven applications with AWS sam and python we built an e-commerce ordering service using AWS SAM, API Gateway, Lambda and Python. Here's the solutions architecture. In that workshop, whenever a ne...

Github Repository https://github.com/EducloudHQ/introduction_to_gen_ai Skill up with serverless on Educloud https://www.educloud.academy/content/da99ad07-7efa-41e7-ba50-b18e6b89e10d This post is an introductory lesson to building AI-enhanced serverle...

Introduction Serverless computing is a cloud-based approach to application development that eliminates the need for provisioning and managing servers. Instead, developers focus on writing code that is triggered by events such as HTTP requests or data...

https://github.com/trey-rosius/sam_stepfunctions Hey!!! How you doing? In this post, we’ll look at how to build a workflow, using SAM as IaC, Appsync, and python. Prerequisites Install AWS Cli (https://docs.aws.amazon.com/cli/latest/userguide/cli-c...

In Part 1 of this series, we modeled and designed access patterns for our application entities.
In Part 2, we designed the primary key and Global Secondary Index, created a sample database schema using NoSql Workbench, and saw clearly each access pattern for our app.
In Part 3, we started coding up our API. We created a project using SAM and wrote a couple of scripts to Create a user, Get a user by ID and also create a post.
For this Fourth article, we will continue from where we left off in part 3.We need to create scripts for
import json
import logging
import os
import time
import uuid
import boto3
dynamodb = boto3.resource('dynamodb')
def update_post(event, context):
data = json.loads(event['body'])
if 'status' not in data:
logging.error("Validation Failed")
raise Exception("Couldn't create the post")
timestamp = str(time.time())
table = dynamodb.Table(os.environ['TABLE_NAME'])
# write the post to the database
item = table.update_item(
Key={
'PK': "USER#{}".format(data['userId']),
'SK': "POST#{}".format(event['pathParameters']['postId'])
},
ExpressionAttributeNames={
"#pt": 'postText',
'#st': 'status',
},
ExpressionAttributeValues={
':postText': data['postText'],
':status': data['status'],
':updatedAt': timestamp,
},
UpdateExpression='SET #pt = :postText,#st=:status, '
'updatedAt = :updatedAt',
ReturnValues='ALL_NEW',
)
# create a response
response = {
"statusCode": 200,
"body": json.dumps(item["Attributes"])
}
return response
Take note of the UpdateExpression. We are updating the values of the postText, status, and updatedAt. We use the ExpressionAttributeNames to define placeholders in an Amazon DynamoDB expression as an alternative to an actual attribute name. An expression attribute name must begin with a pound sign (#) and be followed by one or more alphanumeric characters. (#pt for postText and #st for status)
Expression attribute values in Amazon DynamoDB are substitutes for the actual values that you want to compare—values that you might not know until runtime. An expression attribute value must begin with a colon (:) and be followed by one or more alphanumeric characters.(':postText': data['postText'],':status': data['status'], ':updatedAt': timestamp).
ReturnValues='ALL_NEW' returns all the attributes of the Item as they appear after the updateItem operation.
Let's add the UpdatePostFunction to our SAM template.yaml file.
UpdatePostFunction:
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: posts/
Handler: update.update_post
Runtime: python3.8
Policies:
- DynamoDBCrudPolicy
Events:
HttpPost:
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: /post/{id}
Method: put
Take note, the HTTP method is put since we are updating a record. The endpoint is /post/{id} where id is the ID of the post we want to update.
This request spans two entity types -- the User entity and the Post entity. However, this doesn’t mean we need to make multiple requests.
This script shows how you can structure your code to retrieve both a User entity and the Post entities that were uploaded by the user in a single request
Create a file in the users folder called query.py and type in the following code.
import os
import json
import boto3
import decimalencoder
from botocore.exceptions import ClientError
from boto3.dynamodb.conditions import Key
dynamodb = boto3.resource('dynamodb')
def fetch_user_and_posts(event, context):
# print(event)
# print(event['pathParameters'])
print("print this ")
table = dynamodb.Table(os.environ['TABLE_NAME'])
userId = 'USER#{}'.format(event['pathParameters']['id'])
metadata = 'METADATA#{}'.format(event['pathParameters']['id'])
print(userId)
print(metadata)
result = table.query(
KeyConditionExpression=
Key('PK').eq(userId) & Key('SK').between(metadata, 'POST$'),
ScanIndexForward=True
)
# create a response
response = {
"statusCode": 200,
"body": json.dumps(result["Items"],
cls=decimalencoder.DecimalEncoder)
}
print(response)
print("Query successful.")
return response
At the top, we import the Boto 3 library and some other classes to help structure our code.
The real work is happening in the query_user_details function that’s defined in the script.
In this function, we first get the id parameter from the URL (users/{id}/posts). This Id parameter represents the userId for which we want to retrieve information. The Query specifies a HASH key of USER#UserId to isolate the returned items to a particular user.
Then, the Query specifies a RANGE key condition expression that is between METADATA#UserID and POST$. This Query will return a User entity, as its sort key is METADATA#, as well as all of the Post entities for this user, whose sort keys start with POST#. Sort keys of the String type are sorted by ASCII character codes. The dollar sign ($) comes directly after the pound sign (#) in ASCII, so this ensures that we will get all of the Post entities.
Once we receive a response, we send it back through the API.
Then we Configure the FetchUserAndPosts function in our SAM template.yaml
GetPostPerUserFunction:
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: users/
Handler: query.fetch_user_and_posts
Runtime: python3.8
Policies:
- DynamoDBCrudPolicy
Events:
HttpPost:
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: /users/{id}/posts
Method: get
In order to keep this post short and concise, we'll build and test all scripts we've already written. In the next post, we'll look at creating comments, getting all comments for a given post and also querying a Global Secondary Index.
Get the complete source code from here and let's begin deploying.
Build the SAM project using
sam build --use-container
After successfully building the project, deploy it using
sam deploy --guided
Here's a screenshot of the steps I took to deploy the app. You can use it for guidance

Once deployed successfully, you should see all URL endpoints for your application.

I'll be using Postman to test the API. You can use any API development client of your choice.
Log into your aws account and navigate to the DynamoDB to see the user data in the data table.

You can go ahead and create multiple posts for this user. Also, make sure the data is being saved correctly in the DynamoDB table(data).
And there you have it, user entity and post entities.
As a little challenge, you can go ahead to test the other scripts like
In the next post, we'll write scripts to create comments, retrieve comments for post, and also query a Global Secondary Index.
Thanks for reading. If you found this post helpful, please leave feedback by commenting or liking it.
And till next time my brothers and sisters ✌🏿