9

I have a simple Python function on AWS Lambda that just puts some data into a DynamoDB table and as far as I can tell, I'm following the correct format as per the Boto3 documentation for the put_item() function. I'm getting the following error that I can't seem to debug:

"errorMessage": 
"Parameter validation failed:\nInvalid type for parameter 
Item.GSRResults.L[0], value: 3.8, type: <class 'float'>, valid types: <class 'dict'>
\nInvalid type for parameter Item.GSRResults.L[1], value: 3.4, type: <class 'float'>, valid types: <class 'dict'>\... snip...
\nInvalid type for parameter Item.GSRResults.L[9], value: 3.3, type: <class 'float'>, valid types: <class 'dict'>",
  "errorType": "ParamValidationError",
  "stackTrace": [
    [
      "/var/task/index.py",
      39,
      "upload_test",
      "Item=item"
    ], 

Here is the Python function:

def upload_test(event, context):
    if event['httpMethod'] == 'POST':
        info = event['body']
        item = info['Item']
        return respond(None, dynamo.put_item(
            TableName="TestResults",
            Item=item))

This is the JSON I am sending:

{
  "body": {
    "Item": {
      "UID": {
        "S": "U999999"
      },
      "PID": {
        "S": "P444444"
      },
      "GSRResults": { "L": [3.8,3.4,3.3,2.8,1.3,3.2,4.3,2.1,3.2,3.3] }
    }
  },
  "httpMethod": "POST"
}
empty_space
  • 135
  • 1
  • 1
  • 7

2 Answers2

16

Use the following Client.put_item example for the Client API:

import boto3
client = boto3.client('dynamodb')

item1 = {
  "id": {
    "S": "1",
  },
  "name": {
    "S": "Testing"
  },
  "age": {
    "N": "22"
  },
  "grades": {
    "L": [ {"N": "3.50"}, {"N": "3.1415926"} ]
  }
}

client.put_item(TableName='test', Item=item1);

Or use the following Table.put_item example for the Resource API:

import boto3
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('test')

item2 = {
  "id": "2",
  "name": "Testing2",
  "age": 22,
  "grades": [ decimal.Decimal('3.50'), decimal.Decimal('3.1415926') ]
}

table.put_item(Item=item2)

It's very easy to find that you are using a Resource-level object (such as Table) but accidentally looking at the Client-level API documentation because the methods unfortunately have the same names (e.g. put_item).

See a related post on when to use a boto3 Client vs a Resource. The key difference here is that the Resource API marshals/unmarshals data to/from native Python data types automatically, while the Client API does not.

jarmod
  • 71,565
  • 16
  • 115
  • 122
  • 1
    This did it, thank you so much! This is my first time working with Lambda and DynamoDB so I'm still learning how to properly format all of the data. I guess when retrieving the data I would need to parse this list of dicts and get all the values in a list. Kind of inconvenient but at least this is working now. – empty_space Nov 01 '17 at 18:19
  • so much time wasted - thank you!:) – barakcaf Jun 02 '22 at 13:24
1

The float values should be set as demical in Python.

Import:-

import decimal

Set the value as decimal:-

"GSRResults": [decimal.Decimal('3.8'),decimal.Decimal('3.4')]

Dynamodb Type for Python

For types that involve numbers, it is recommended that Decimal objects are used to be able to round-trip the Python type.

notionquest
  • 37,595
  • 6
  • 111
  • 105
  • I tried this and it's still complaining that the type is not dict. – empty_space Nov 01 '17 at 17:52
  • I have tested it. It works fine for me. I don't have type "L" explicitly in the json string. My jsonString = {"storage_CACHE_KEY": "2", "GSRResults": [decimal.Decimal('3.8'),decimal.Decimal('3.4')] } – notionquest Nov 01 '17 at 17:54