DEV Community

Cover image for Custom DynamoDB Unmarshal into Golang Struct
Benjamen Pyle for AWS Community Builders

Posted on • Originally published at binaryheap.com

5

Custom DynamoDB Unmarshal into Golang Struct

Short post on unmarshalling a DynamoDB Map into something strongly typed like a Go struct. If you want to jump straight to some code, here are the Github gists

So what is "unmarshalling"? It's the act of taking one representation of data and converting it into another. For instance when we store data in DynamoDB one of the native data types is a "map". A map is really nothing more than a dictionary/key value type look up. Think of a dictionary as a data structure that has a key and a subsequent value. The key must be unique. Take this data for example


{
  "Roles": {
    "1": {
      "name": "Role number 1",
      "id": 1
    },
    "2": {
      "name": "Role number 2",
      "id": 2
    }
  },
  "SK": "ROLE#1234",
  "PK": "USERPROFILE#1000130",
  "EntityType": "UserRole"
}
Enter fullscreen mode Exit fullscreen mode

The Roles property is a map. It contains keys of ["1"] and ["2"]. Then each of those keys contain another map inside of it. These look alot like JSON objects and for all intents and purposes, it's OK to think of them like that.

So with this data, how to do we get it into something that looks like this

type UserRole struct {
    EntityType string `dynamodbav:"EntityType"`
    Roles      []Role `dynamodbav:"Roles"`
}

type Role struct {
    Id   int
    Name string
}</pre>
Enter fullscreen mode Exit fullscreen mode

The UserRole struct has en EntityType property as well as a Roles slice that holds Role structs. Each field also has attributes that describe them as things that are represented in DyanamoDB Attribute values with names that correspond to the column names. Feel free to read up more here

To get started with the unmarshalling the first step is to build a UserRole and unmarshall it.


ur := &amp;UserRole{}
_ = dynamodbattribute.UnmarshalMap(i, ur)</pre>
Enter fullscreen mode Exit fullscreen mode

By default, this is going to really just unmarshal the fields that the Go library knows how to deal. So very similar to when working with JSON unmarshalling, the same can be done with DynamoDB

func (ur *UserRole) UnmarshalDynamoDBAttributeValue(value *dynamodb.AttributeValue) error {
    for k, kv := range value.M {
        if k == "EntityType" {
            ur.EntityType = *kv.S
        } else if k == "Roles" {
            for _, nkv := range kv.M {
                r := &amp;Role{}
                err := dynamodbattribute.UnmarshalMap(nkv.M, r)
                if err != nil {
                    return err
                }
                ur.Roles = append(ur.Roles, *r)
            }
        }
    }
    return nil
}
Enter fullscreen mode Exit fullscreen mode

Note that you can spin through the Key/Value pairs of the attribute value that is passed in. For each of the keys, you can determine what type of object is inside there. For instance the EntityType field is a string. So that's simple enough.

But with the Roles field, there is another map to deal with. So again, simply unmarshal that variable and take the custom step one layer further

func (r *Role) UnmarshalDynamoDBAttributeValue(value *dynamodb.AttributeValue) error {
    for k, kv := range value.M {
        if k == "id" {
            v, _ := strconv.ParseInt(*kv.N, 10, 32)
            r.Id = int(v)
        } else if k == "name" {
            r.Name = *kv.S
        }
    }

    return nil
}
Enter fullscreen mode Exit fullscreen mode

And there it is. An umarshalled custom type from a DynamoDB map. There isn't too much more too it but this super powerful as you can realize any type of data stored in DynamoDB into a Go struct with your custom code.

Hope this was helpful!

Sentry image

Hands-on debugging session: instrument, monitor, and fix

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

RSVP here →

Top comments (0)

Create a simple OTP system with AWS Serverless cover image

Create a simple OTP system with AWS Serverless

Implement a One Time Password (OTP) system with AWS Serverless services including Lambda, API Gateway, DynamoDB, Simple Email Service (SES), and Amplify Web Hosting using VueJS for the frontend.

Read full post

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay