Search code examples
jsongoamazon-dynamodbmarshalling

How to marshal JSON with lowercase keys


I use AWS Lambda with DynamoDB using golang.

My DynamoDB table use lowercase attribute names such as id or name.

In Go, if I want to be able to marshal a struct correctly, I have to name fields starting with a capital letter.

type Item struct {
    ID   string
    Name string
}

To put an item into my DynamoDB table, I have to marshal it into a map[string]*dynamodb.AttributeValue, using dynamodbattribute.MarshalMap function.

item := Item{
    ID: "xxxx",
    Name: "yyyy"
}

av, _ := dynamodbattribute.MarshalMap(item)

Of course, this will create a map using names written as ID and Name, which are incompatible with id and name from the dynamodb table.

Reading the documentation, I found that you can use a custom encoder, and enable json tags.

type Item struct {
    ID   string  `json="id"`
    Name string  `json="name"`
}

func setOpts(encoder *dynamodbattribute.Encoder) {
    // Not sure which one I sould set
    // So I set them both :)
    encoder.SupportJSONTags = true
    encoder.MarshalOptions.SupportJSONTags = true
}

func main() {
    encoder := dynamodbattribute.NewEncoder(setOpts)

    encoder.Encode(...)
}

But here the encoder.Encode() method is only used to create a dynamodb.AttributeValue, and not a map[string]*dynamodb.AttributeValue.

Is there a way to use a custom encoder with MarshalMap? Or am I using it in a wrong way?

EDIT:

Okay so as Zak pointed out, there is a dynamodbav tag that can be used.

I also found out that I was using json tags in a wrong way. I should use the syntax json:"id" instead of json="id".

Indeed, DynamoDB SDK uses the json tag if available, and this one can be overrided by the dynamodbav.

So all I had to do was to make my structure looks like this and it worked

type Item struct {
    ID   string  `json:"id"`
    Name string  `json:"name"`
}

Solution

  • Dynamo's built in marshalling, from MarshalMap(...) can support struct tags, similar to json.

    You can add them to the type that you are marshalling, like so:

    type Item struct {
        ID   string `dynamodbav:"id"`
        Name string `dynamodbav:"name"`
    }
    

    See the docs here