fbpx

How to return multiple attributes from DynomoDB via a Lambda Function and API Gateway

I have just been developing a server-less API that returns attributes from a DynamoDB database and ran into some trouble returning multiple attributes at once via URL query strings. The purpose of this blog help people who are having the same difficulties.

Why do I want to return multiple attributes at once anyway?

There are two reasons why I want to return multiple attributes. The first is because I do not want to return an entire row from my DynamoDB table. If I did, it would impact performance due to the some of my attributes containing very large JSON objects. The second is also improve performance and reduce costs by returning all the attributes I need in a single call to the DynamoDB table rather than multiple calls to receive each attribute.

How to call multiple attributes from DynamoDB using Lambda and API Gateway

To call multiple attributes (columns) from a DynamoDB table is a three step process

Step 1: Adding AttributesToGet to table.get_item()

The first step involved updating the DynamoDB query to include AttributesToGet which needs to be a list of all the attributes. e.g. [“attribute 1″,”attribute 2″,”attribute 3”]

# Returning the entire row (all attributes) from DynamoDB
response = table.get_item(Key = "Partition Key")
# Returning the specific attributes from a row in DynamoDB
response = table.get_item(Key = "Partition Key", AttributesToGet = "attribute name")

Step 2: Retrieving values from the multiValueQueryStringParameters event field

The queryStringParameters event field only returns single event fields. If you want to assign multiple values to the same field, then you need to make use of the multiValueQueryStringParameters event.

partition_key = event['queryStringParameters']['partition_key']
attributes = event['multiValueQueryStringParameters']['attribute']

This allows you to pass in multiple attributes to a single query string. So the below API URL would pass the following to your Lambda Function: partition_key=”x12345″ and attribute=[“column1″,”column2”]

https://api.yoururl.com/v3/lambda-function-name?partition_key=x12345&attribute=column1&attribute=column2

Resoving “errorMessage”: “Object of type Decimal is not JSON serializable”

If you are getting “errorMessage”: “Object of type Decimal is not JSON serializable”, it is caused by DynamoDB storing floats as Decimals which are not able to be encoded by json.dumps(). To get around this, you can convert Decimals from DynamoDB to floats before encoding into JSON using json.dumps(). To do this, you can use the code below:

from decimal import Decimal

class DecimalEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, Decimal):
            return float(obj)
        return json.JSONEncoder.default(self, obj)

Now just update your json.dumps() code to include cls=DecimalEncoder and the issue is resolved!

response = {"statusCode":200,"body":json.dumps(response["Item"],cls=DecimalEncoder)}

Full Lambda Function to pull specific attributes from DynamoDB

# API Gateway URL
https://api.yoururl.com/v3/lambda-function-name?partition_key=x12345&attribute=column1&attribute=column2
import json
import boto3
from boto3.dynamodb.conditions import Key
from decimal import Decimal

# Convert Decimal to float
class DecimalEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, Decimal):
            return float(obj)
        return json.JSONEncoder.default(self, obj)


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

    # Get query strings passed in from API
    partition_key = event['queryStringParameters']['partition_key']
    attribute = event['multiValueQueryStringParameters']['attribute']

    # Get item by Locality ID
    PartitionKey = {'partition_key': partition_key}

    response = table.get_item(Key=PartitionKey,AttributesToGet=attribute)
    response = {"statusCode":200,"body":json.dumps(response["Item"],
                       cls=DecimalEncoder)}
    
    return response

Recent Posts