'Error when doing a PUTITEM type: <class 'str'>, valid types: <class 'dict'>

When doing a putitem to dynamo it is giving me the following error, the json I am reading from s3. this is the code

   dictItems = json.load(object_summary.get()['Body'])
   item2 =  {
                    "ruc" : dictItems['ruc'],
                    "dni" :dictItems['dni'],
                    "number_operation" :dictItems['number_operation'],
                    "name" :dictItems['name'],
                    "address" :dictItems['address'],
                    "validation_date" :dictItems['validation_date'],
                    "directory" :dictItems['directory'],
                    "addresses" :dictItems['addresses'],
                    "representatives"  :dictItems['representatives'],
                    "sunat"  :dictItems['sunat'],
                    "debt"  :dictItems['debt'],
                    "bad_debtor_portfolio" :dictItems['bad_debtor_portfolio'],
                    "foreign_trade" :dictItems['foreign_trade'],
                    "legal_information" :dictItems['legal_information'],
                    "query_indicator" :dictItems['query_indicator'],
                    "claim_review": dictItems['claim_review']
                    }
    dynamodb = boto3.client('dynamodb')
    dynamodb.put_item(TableName='temporal', Item=item2)

this is the error

Parameter validation failed: Invalid type for parameter Item.ruc, value: 789456123, type: <class 'str'>, valid types: <class 'dict'> Invalid type for parameter Item.dni, value: , type: <class 'str'>, valid types: <class 'dict'> Invalid type for parameter Item.number_operation, value: XXXXXXXXXX, type: <class 'str'>, valid types: <class 'dict'> Invalid type for parameter Item.name, value: THIS IS A STRING, type: <class 'str'>, valid types: <class 'dict'>



Solution 1:[1]

As the error specified, the input data type has to be a dictionary instead of a string.

Do this instead:

   dictItems = json.load(object_summary.get()['Body'])
   item2 =  {
                    "ruc" : {'N': dictItems['ruc']},
                    ...
                    }
    dynamodb = boto3.client('dynamodb')
    dynamodb.put_item(TableName='temporal', Item=item2)

where "ruc" : dictItems['ruc'] is change to "ruc" : {'N': dictItems['ruc']}.

Solution 2:[2]

As explained in detail here in DynamoDB's documentation, DynamoDB's low-level API is JSON based and because JSON data types do not exactly correspond with DynamoDB's types, there is a more complicated representation of the different types. For example, to send the number 789456123 you wanted to send as part of the request, you can't simply send this number - instead you need to send the following object: { "N": "789456123"}. This is a map, the key is the type ("N" means a number) and the value is the content of this number - a JSON string, not a JSON number, so as not to loose precision when the JSON library handles it).

The boto3's "client" library, which you are using, uses this low-level API, so you must pass { "N": "789456123"} instead of 789456123.

But there's a better and easier approach: boto3 also has a "resource" library, which gives you more or less the same functions - but their parameters are normal Python types instead of low-level API objects. So you can pass a Python integer normally, and it will be passed to the API as a "number" object without you needing to do this conversion explicitly. You also get to enjoy the opposite conversion when you read from the table.

You should switch your code to use a "resource" instead of a "client".

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Nadav Har'El