Search⌘ K
AI Features

REST API with DynamoDB Integration

Understand how to create a REST API integrated with DynamoDB through AWS API Gateway to implement atomic counters. Explore using UpdateItem and PutItem APIs, request and response mappings with Velocity templates, and how to maintain atomicity in distributed systems. Gain practical knowledge to deploy and test APIs managing event counters securely and efficiently.

We'll cover the following...

Atomic counter

Every architect dreams of an independent distributed system where all transactions process independently of the others. Such ideals remain ideals. Despite all the care, we do end up with scenarios where we need some shared resources like counters. An atomic counter is required in many applications. We need a way to count events and assign a unique number to events while ensuring we do not have a race condition.

Note: Atomicity on a distributed, eventually consistent database may seem counterintuitive, but we can make it work with a trick. We can configure the DynamoDB updates to return the updated value immediately. So, the update may take time to propagate within the database. However, the API invoking the update gets the updated value without conflict. AWS documentation gives more details about it.

Implementation

The DynamoDB APIs are POST, requiring the data in the request body. The URL is specific to the actual action we perform on the database. The rest of the information (table name and other details required for the action) is included in the request body. The DynamoDB API documentation provides details of the exact content of this payload for each operation on the DynamoDB.

In our example, we implement the atomic counter using the UpdateItem API. The payload request body for this API is generated through the API integration by using a Velocity template. The response to this UpdateItem API has the updated value. The response integration removes the unwanted parts of the response body and returns only the counter value.

Let’s check the code.

#!/bin/sh -v

# -----------------------------------------------------------------
# Configure the AWS CLI to let it communicate with your account
# -----------------------------------------------------------------
aws configure set aws_access_key_id $aws_access_key_id
aws configure set aws_secret_access_key $aws_secret_access_key
aws configure set region us-east-1

# -----------------------------------------------------------------
# Delete any old deployments
# -----------------------------------------------------------------
# 1. Trigger CloudFormation stack delete
# 2. Wait for the stack to be deleted 
aws cloudformation delete-stack --stack-name  EducativeCourseApiGateway
aws cloudformation wait stack-delete-complete --stack-name EducativeCourseApiGateway


# -----------------------------------------------------------------
# External API, no Lambda function. Initiate the CloudFormation deployment.
# -----------------------------------------------------------------
aws cloudformation deploy \
    --template-file template.yml \
    --stack-name EducativeCourseApiGateway \
    --capabilities CAPABILITY_NAMED_IAM \
    --parameter-overrides DeployId="$RAND" SourceCodeBucket="educative.${bucket}" \
    --region us-east-1

# -----------------------------------------------------------------
# Get the API ID of the Rest API we just created.
# -----------------------------------------------------------------
apiId=`aws cloudformation list-stack-resources --stack-name EducativeCourseApiGateway | jq -r ".StackResourceSummaries[3].PhysicalResourceId"`
echo "API ID: $apiId"

# -----------------------------------------------------------------
# This is the URL for the API we just created
# -----------------------------------------------------------------
url="https://${apiId}.execute-api.us-east-1.amazonaws.com/v1"
echo $url

# -----------------------------------------------------------------
# Invoke the URL to test the response
# -----------------------------------------------------------------

# 1. Initialize the counter

curl --location --request PUT $url --header 'Content-Type: application/json' --data-raw '{}'

# 2. Increment the counter 
curl --location --request GET $url --header 'Content-Type: application/json' 

# 3. Increment the counter again
curl --location --request GET $url --header 'Content-Type: application/json' 

# 4. Increment the counter yet again
curl --location --request GET $url --header 'Content-Type: application/json' 

Click "Run" to trigger the script to deploy the API. It deploys the CloudFormation template that includes the DynamoDB table integrated with the API Gateway. The PUT method initiates the counter to `1`. Subsequent GET requests return the current value of the counter and then increment it by `1`. Let’s check out the code to see how this works.

  • Line 10 creates the DynamoDB table.

  • Line 35 creates a GET method in the REST API.

  • Line 46 integrates the API with UpdateItem on the DynamoDB table.

  • Line 50 defines the data mapping on the response body. This extracts the number out of the entire response body.

  • Line 52 defines the data mapping on the request body. It builds the payload for the UpdateItem API.

  • Line 56 creates the PUT method in the REST API.

  • Line 67 integrates the API with PutItem on the DynamoDB table.

  • Line 71 defines the mapping on the request body. It builds the payload for the PutItem API.

Web console

Let’s now check how this looks on the UI. First, open the API Gateway console. Then, click “EducativeRestAPI” to view the two methods and their configuration in detail.

Note the following points in the web console integration request/response:

  • The integration type is "AWS Service," which is set to "DynamoDB." The HTTP method is "POST."

  • The action is UpdateItem in the GET method, where the counter is incremented with an atomic update.

  • The Velocity template for mapping the data is provided in the mapping template. This builds a JSON request for the UpdateItem API on DynamoDB.

  • The integration response has another mapping template that extracts the number out of the entire JSON returned by the UpdateItem.

  • The action is PutItem in the PUT method.

  • The Velocity template for mapping the data is provided in the mapping template. This builds the JSON request for the PutItem on DynamoDB.

As an experiment, try to extend this API to implement atomic decrementation.