DEV Community

Cover image for Challenge: Create DynamoDB Table using Python (Boto3)
Sri for AWS Community Builders

Posted on • Updated on

Challenge: Create DynamoDB Table using Python (Boto3)

Challenge: Create DynamoDB Table using Python (Boto3)

This was an idea from the AWS Certified Global Community to create challenges by breaking a certain part of code, so the users can learn by fixing the code.

I have written this challenge for the AWS Certified Global Community and have also used it to mentor some of my mentees.
I thought that it might be a good idea to share with the broader community as well.

Boto3 is the name of the Python SDK for AWS. It allows you to directly create, update, and delete AWS resources from your Python scripts.

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.

Let's start the challenge!

Pre-Requisites:

  • Lambda with Python 3.9
  • Lambda Execution role with access to DynamoDB and CloudWatch access (IAM)

Step 1. Create an IAM Policy:

Note: Replace [Region] and [AccountID] in the Policy

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "dynamodb:CreateTable",
                "dynamodb:DescribeTable",
                "dynamodb:BatchGetItem",
                "dynamodb:GetItem",
                "dynamodb:Query",
                "dynamodb:Scan",
                "dynamodb:BatchWriteItem",
                "dynamodb:PutItem",
                "dynamodb:UpdateItem"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:[Region]:[AccountID]:*"
        },
        {
            "Effect": "Allow",
            "Action": "logs:CreateLogGroup",
            "Resource": "*"
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

Step 2. Create a role for Lambda and attach the policy created in Step 1

Trusted entities:
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "lambda.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}
Enter fullscreen mode Exit fullscreen mode

Step 3. Broken Code: Create a Lambda function with the following code and execute the function.

import boto3
import json

def lambda_handler(event, context):
    client = boto3.resource('dynamodb')

    table_name = 'VisitsCount'
    params = {
        'TableName': table_name,
        'KeySchema': [
            {'AttributeName': 'partition_key', 'KeyType': 'HASH'},
            {'AttributeName': 'sort_key', 'KeyType': 'RANGE'},
        ],
        'AttributeDefinitions': [
            {'AttributeName': 'Date', 'AttributeType': 'S'},
            {'AttributeName': 'Count', 'AttributeType': 'N'}
        ],
        'ProvisionedThroughput': {
            'ReadCapacityUnits': 10,
            'WriteCapacityUnits': 10
        }
    }
    table = client.create_table(**params)
    print(f"Creating {table_name}...")
    table.wait_until_exists()

    return {
        'statusCode': 200,
        'body': table
    }    
Enter fullscreen mode Exit fullscreen mode

First Error: We get the following error when we execute the code.

 'KeySchema': [
            {'AttributeName': 'partition_key', 'KeyType': 'HASH'},
            {'AttributeName': 'sort_key', 'KeyType': 'RANGE'},
        ],
Enter fullscreen mode Exit fullscreen mode
Error Message:
{
  "errorMessage": "An error occurred (ValidationException) when calling the CreateTable operation: One or more parameter values were invalid: Some index key attributes are not defined in AttributeDefinitions. Keys: [partition_key, sort_key], AttributeDefinitions: [Date, Count]",
  "errorType": "ClientError",
  "requestId": "b4f6cf89-8efb-470b-a52e-81d364d5e7a2",
  "stackTrace": [
    "  File \"/var/task/lambda_function.py\", line 23, in lambda_handler\n    table = client.create_table(**params)\n",
    "  File \"/var/runtime/boto3/resources/factory.py\", line 520, in do_action\n    response = action(self, *args, **kwargs)\n",
    "  File \"/var/runtime/boto3/resources/action.py\", line 83, in __call__\n    response = getattr(parent.meta.client, operation_name)(*args, **params)\n",
    "  File \"/var/runtime/botocore/client.py\", line 391, in _api_call\n    return self._make_api_call(operation_name, kwargs)\n",
    "  File \"/var/runtime/botocore/client.py\", line 719, in _make_api_call\n    raise error_class(parsed_response, operation_name)\n"
  ]
}
Enter fullscreen mode Exit fullscreen mode

Fix for the error: Upate the following code block.

'KeySchema': [
            {'AttributeName': 'Date', 'KeyType': 'HASH'},
            {'AttributeName': 'Count', 'KeyType': 'RANGE'},
        ],
Enter fullscreen mode Exit fullscreen mode

Reference/Hint: Ceating dynamodb table says "invalid One or more parameter values were invalid: Some index key attributes are not defined in AttributeDefinitions"


So when we execute the code, this time we get another error as following

Second Error: We get the following error when we execute the code after applying fix for the first error.
The issue is while prinintg the table name in the output

'body': table
Enter fullscreen mode Exit fullscreen mode
Error Message:
{
  "errorMessage": "Unable to marshal response: Object of type dynamodb.Table is not JSON serializable",
  "errorType": "Runtime.MarshalError",
  "requestId": "e60ca4f2-eccd-410c-a93a-7cf7499a0a9d",
  "stackTrace": []
}
Enter fullscreen mode Exit fullscreen mode

Fix for the error: Upate the following code block.

'body': json.dumps(table_name)
Enter fullscreen mode Exit fullscreen mode

Reference/Hint: AWS Lambda "Unable to marshal response" Error


Step 4. Final Code:

import boto3
import json

def lambda_handler(event, context):
    client = boto3.resource('dynamodb')

    table_name = 'VisitsCount'
    params = {
        'TableName': table_name,
        'KeySchema': [
            {'AttributeName': 'Date', 'KeyType': 'HASH'},
            {'AttributeName': 'Count', 'KeyType': 'RANGE'},
        ],
        'AttributeDefinitions': [
            {'AttributeName': 'Date', 'AttributeType': 'S'},
            {'AttributeName': 'Count', 'AttributeType': 'N'}
        ],
        'ProvisionedThroughput': {
            'ReadCapacityUnits': 10,
            'WriteCapacityUnits': 10
        }
    }
    table = client.create_table(**params)
    print(f"Creating {table_name}...")
    table.wait_until_exists()

    return {
        'statusCode': 200,
        'body': json.dumps(table_name)
    }
Enter fullscreen mode Exit fullscreen mode
Output:
Test Event Name
createtable

Response
{
  "statusCode": 200,
  "body": "\"VisitsCount\""
}
Enter fullscreen mode Exit fullscreen mode

Hope you liked the challenge! Please let me know your thoughts in the comments section.

See you next time 👋


References:

DynamoDB CreateTable


Top comments (0)