Aws-sdk-ios: DynamoDB mapper sending empty values

Created on 29 Sep 2017  路  9Comments  路  Source: aws-amplify/aws-sdk-ios

I'm trying to use DynamoDB using the iOS Swift SDK. I'm using Cognito with Facebook as an external identity provider. Cognito is working fine - I've tested user sync and it works OK, so I believe I have the authentication set up. Here's how I'm setting up the SDK (I have the actual values of my identity pool in my code):

 let credentialsProvider = AWSCognitoCredentialsProvider(regionType:.USEast1,
                                                                identityPoolId:"<my-identity-pool-id>", identityProviderManager: FacebookProvider())

        let configuration = AWSServiceConfiguration(region:.USEast1, credentialsProvider:credentialsProvider)
        AWSServiceManager.default().defaultServiceConfiguration = configuration

And here's my DynamoDB mapped class:

import Foundation
import AWSDynamoDB

class SavedItem : AWSDynamoDBObjectModel, AWSDynamoDBModeling {

    var userId : Int?
    var timestamp : Int?

    static func dynamoDBTableName() -> String {
        return "my-table"
    }

    class func hashKeyAttribute() -> String {
        return "userId"
    }

    class func rangeKeyAttribute() -> String {
        return "timestamp"
    }
 }

I've verified that my code has the correct table and attribute names and that the hash key and range key values on the table are identical, including case sensitivity, with the fields in my SavedItem class.

Here's how I'm instantiating the mapper:

let dynamoDBObjectMapper = AWSDynamoDBObjectMapper.default()

        let savedItem = SavedItem()
        savedItem?.userId = 1
        savedItem?.timestamp = 2

        dynamoDBObjectMapper.save(savedItem!).continueWith(block: { (task:AWSTask<AnyObject>!) -> Any? in
            if let error = task.error as? NSError {
                print("The request failed. Error: \(error)")
            } else {
                // Do something with task.result or perform other operations.
                print("Save callback executing")
            }

            return nil
        })

That code's more or less straight out from the AWS Documentation example. But, here's what I get back in the console when that code executes:

 Error Domain=com.amazonaws.AWSCognitoIdentityErrorDomain Code=0 "(null)" UserInfo={__type=com.amazon.coral.validate#ValidationException, message=Supplied AttributeValue is empty, must contain exactly one of the supported datatypes}

I bumped console logging up to debug, and it looks like the mapper is not sending any attributes from the SavedItem object. Here's what's in the console for the save request body:

Request body:
{"Key":{"userId":{},"timestamp":{}},"TableName":"my-table","AttributeUpdates":{}}

Did I screw something up, or is the mapper not serializing the object correctly when serializing it for a request?

To help us solve your problem better, please answer the following list of questions.

  • What service are you using?

DynamoDB with a Cognito Federated Identity provider

  • In what version of SDK are you facing the problem?

v2.6.1

  • Is the issue limited to Simulators / Actual Devices?

Happening in the simulator, unsure if happening on the actual device.

  • Can your problem be resolved if you bump to a higher version of SDK?

There is nothing in the changelog about DynamoDB for 2.6.2

  • Is this problem related to specific iOS version?

  • How are you consuming the SDK? CocoaPods / Carthage / Prebuilt frameworks?

Cocoapods

  • Can you give us steps to reproduce with a minimal, complete, and verifiable example? Please include any specific network conditions that might be required to reproduce the problem.

See description above.

dynamodb pending investigation

Most helpful comment

Hi,
I have been facing same issue for some time but was able to find a solution to this here

if you are using Swift 4 then you need to add @objcMembers on top of the class definition line as shown below. This worked for me

import AWSDynamoDB

@objcMembers
class TableName: AWSDynamoDBObjectModel, AWSDynamoDBModeling {
}

And just to add a check before you save(put) into the table, check if user sign in was successful, if not call the AWSAuthUIViewController.presentViewController to authorise.

Hope this helps!

All 9 comments

Hello Ryan,

Thanks for using our SDK and reporting to us. Sorry for the inconvenience caused.
DynamoDBMapper doesn't support sending empty strings whether it's a primary key or not. You can instead use NULL. This is a known limitation.

Workaround:

  1. You can use NULL.
  2. You can encode "" (empty string) with another character and treat that differently in the application.

Hey there, thanks for taking a look at this and getting back to me.

I'm not sure that solves my problem though; I'm not sending any empty values and none of the properties on my SavedItem class are of type String. I'm setting userId to 1 and timestamp to 2 before calling save() like so:

 let savedItem = SavedItem()
 savedItem?.userId = 1
 savedItem?.timestamp = 2

Hi Ryan,

Thanks for the quick response. As per your reply,
Request body:
{"Key":{"userId":{},"timestamp":{}},"TableName":"my-table","AttributeUpdates":{}}
The request body sent by DynamoDB Mapper has empty userId and timestamp and the exception thrown matches this empty string being sent.
I will look into DynamoDBMapper and get back to you on why the userId and timestamp got empty values in the request.

Did you upgrade the SDK recently? What version of iOS are you running?
Did your table schema got changed recently?

I see in the logs that the Key attributes are empty and that's what's causing the exception, but I'm setting the attributes in my code.

This is occurring in v2.6.1 and v2.6.2 of the SDK on the iOS 11 simulator. No changes to the table schema - this is a brand new table.

@kvasukib, I figured this out. The issue seems to have been that my hash key and range key were of type Int. When I changed them to NSNumber, the save worked correctly.

I think that the AWS Swift SDK documentation should document allowed types (and it might, but I didn't come across it).

Seems like it might be nice to have the SDK check this prior to sending the request to AWS and provide a more helpful message, too.

At any rate, thanks for looking into this.

Thank you for the feedback. We will look into the documentation. Closing the issue.

I got same situation and solved by changing range key type to NSNumber from Int. I could not find any document talking about that solution. Please consider to update error message and document.

I am having similar issues, but I have not Int or NSNumber, I only have String.
I have been trying different things and searching the net for a while, but to no avail.

Hi,
I have been facing same issue for some time but was able to find a solution to this here

if you are using Swift 4 then you need to add @objcMembers on top of the class definition line as shown below. This worked for me

import AWSDynamoDB

@objcMembers
class TableName: AWSDynamoDBObjectModel, AWSDynamoDBModeling {
}

And just to add a check before you save(put) into the table, check if user sign in was successful, if not call the AWSAuthUIViewController.presentViewController to authorise.

Hope this helps!

Was this page helpful?
0 / 5 - 0 ratings