Storing session data from web apps created with API Gateway and Lambda in DynamoDB
This is one of the topics of the AWS DBA, which is related to development with AWS services.
Think about how to handle session information in web apps created with API Gateway and Lambda functions.
In this article, we will show you how to store session information in DynamoDB.
Cookies are used for session management.
Environment
Create a DynamoDB table.
This table will store session information.
Specifically, it stores two pieces of data per session.
- Session ID
- Counter
The counter records the number of times the application is accessed during a session.
Create a Lambda function.
The function’s action is to access DynamoDB, retrieve/store session information, and store the session ID in a cookie.
The runtime environment for the function is Python 3.8.
Create an API Gateway and place a Lambda function on the backend.
When an HTTP request is received from a user, the API Gateway acts as an endpoint, calling a function on behalf of the user and returning the result of the function invocation to the user.
The API Gateway should be of the HTTP API type.
CloudFormation template files
The above configuration is built with CloudFormation.
The CloudFormation templates are placed at the following URL
https://github.com/awstut-an-r/awstut-dva/tree/main/03/006
Explanation of key points of template files
This page focuses on how to manage session information in DynamoDB.
For basic information on HTTP API type API Gateway, please refer to the following pages.
DynamoDB
Resources:
Table:
Type: AWS::DynamoDB::Table
Properties:
AttributeDefinitions:
- AttributeName: session-id
AttributeType: S
BillingMode: PAY_PER_REQUEST
KeySchema:
- AttributeName: session-id
KeyType: HASH
TableName: !Sub "${Prefix}-table"
Code language: YAML (yaml)
Create a DynamoDB table.
For basic information on DynamoDB tables, please refer to the following page.
Set the “session-id” attribute to the table and use this as the partition key.
Lambda
Function
Resources:
Function:
Type: AWS::Lambda::Function
Properties:
Architectures:
- !Ref Architecture
Code:
ZipFile: |
import boto3
import json
import os
import uuid
from http import cookies
ATTR_COUNTER = 'counter'
ATTR_SESSION_ID = 'session-id'
COOKIE_KEY = 'cookie-test'
DYNAMODB_ITEM_KEY = 'Item'
TABLE_NAME = os.environ['TABLE_NAME']
dynamodb_client = boto3.client('dynamodb')
def lambda_handler(event, context):
session_id = ''
if not 'cookies' in event:
session_id = str(uuid.uuid4())
else:
C = cookies.SimpleCookie()
C.load('; '.join([cookie for cookie in event['cookies']]))
cookie_dict = {k: v.value for k, v in C.items()}
if not COOKIE_KEY in cookie_dict:
session_id = str(uuid.uuid4())
else:
session_id = cookie_dict[COOKIE_KEY]
dynamodb_get_item_response = dynamodb_client.get_item(
TableName=TABLE_NAME,
Key={
ATTR_SESSION_ID: {'S': session_id}
}
)
#print(dynamodb_get_item_response)
counter = 0
if not DYNAMODB_ITEM_KEY in dynamodb_get_item_response:
counter = 1
else:
counter = int(
dynamodb_get_item_response[DYNAMODB_ITEM_KEY][ATTR_COUNTER]['N']) + 1
dynamodb_put_item_response = dynamodb_client.put_item(
TableName=TABLE_NAME,
Item={
ATTR_SESSION_ID: {'S': session_id},
ATTR_COUNTER: {'N': str(counter)}
}
)
#print(dynamodb_put_item_response)
body = 'session-id: {session_id}, counter: {counter}'.format(
session_id=session_id,
counter=counter)
set_cookie = '{cookie_key}={session_id}'.format(
cookie_key=COOKIE_KEY,
session_id=session_id)
return {
'statusCode': 200,
'body': body,
'headers': {
'Set-Cookie': set_cookie
}
}
Environment:
Variables:
TABLE_NAME: !Ref Table
FunctionName: !Sub "${Prefix}-function"
Handler: !Ref Handler
Runtime: !Ref Runtime
Role: !GetAtt FunctionRole.Arn
Code language: YAML (yaml)
The code to be executed by the Lambda function in inline format.
For more information, please refer to the following page.
Define environment variables in the Environment property.
Set the table name of the DynamoDB table mentioned above.
The processing to be performed by this function is as follows
- Access cookie information from the event object to obtain a session ID.
If no session ID is registered in the cookie, generate a unique UUID-based ID and use this as the session ID. - Attempt to retrieve an item from the DynamoDB table using the session ID, and if there is a corresponding item, retrieve the counter value.
If there is no corresponding item, set the counter value to 1. - Store the counter value in the DynamoDB table using the session ID as the partition key.
- In the HTTP response header, set the session ID in the cookie.
In the HTTP response body, set a string containing the session ID and counter value.
IAM Role
Resources:
FunctionRole:
Type: AWS::IAM::Role
DeletionPolicy: Delete
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action: sts:AssumeRole
Principal:
Service:
- lambda.amazonaws.com
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: SessionPolicy
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Action:
- dynamodb:GetItem
- dynamodb:PutItem
Resource:
- !Sub "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${Table}"
Code language: YAML (yaml)
Inline policies allow reading and writing to DynamoDB tables.
Architecting
Use CloudFormation to build this environment and check its actual behavior.
Create CloudFormation stacks and check the resources in the stacks
Create CloudFormation stacks.
For information on how to create stacks and check each stack, please refer to the following pages.
After reviewing the resources in each stack, information on the main resources created in this case is as follows
- DynamoDB table: dva-03-006-table
- Lambda function: dva-03-006-function
- API gateway endpoint: dva-03-006-HttpApi
Check each resource from the AWS Management Console.
First, check the DynamoDB table.
You can see that the table has been successfully created with the partition key as “session-id”.
Check the Lambda function.
You can see that the function has been created successfully.
Check the API Gateway.
You can see that the HTTP type API Gateway has been successfully created.
You can also see that the API Gateway and Lambda functions have been integrated.
Action Check
Now that you are ready, access the API Gateway endpoint.
Session ID and counter are displayed.
The counter value is “1”.
Check cookies in the Developer Tool.
Indeed, a session ID is set with the name “cookie-test”.
Access the same page again.
Counter value updated.
Check the DynamoDB table.
The table shows that the session ID and counter values are stored.
Thus, by referring to the cookie value stored in the cookie, the session is continued and the counter value is updated.
Finally, access the same URL in another browser (incognito window).
A new session ID is generated and registered with a counter value of “1”.
Thus, it can be confirmed that session management is done for each browser.
Summary
We have shown you how to store session information in DynamoDB.