Categories
AWS Beginner DynamoDB Go Intermediate tutorial

Testing locally DynamoDB in Go

Testing locally DynamoDB in Go
Testing locally DynamoDB in Go

Testing DynamoDB locally in Go or any language is tricky. In this quick article I will provide a solution on how to test locally using a docker container and your web service that interfaces with AWS DynamoDB.

First, you will need a DynamoDB instance running locally so that you can interact with it from your service.

DynamoDB Instance with Docker-Compose

dynamodb:
    image:  "amazon/dynamodb-local:latest"
    command: "-jar DynamoDBLocal.jar -sharedDb -dbPath ./data"
    container_name: dynamodb
    ports:
      - 8000:8000
    environment:
      AWS_REGION: "us-east-1"
      AWS_ACCESS_KEY_ID: "YOUR_AKID"
      AWS_SECRET_ACCESS_KEY: "YOUR_SECRET_KEY"
      AWS_SESSION_TOKEN: "TOKEN"
    working_dir: "/home/dynamodblocal"
    volumes:
      -  "./docker/dynamodb:/home/dynamodblocal/data"

The code above shows you how to create a simple DynamoDB instance for you to test with locally user a docker-compose.yml file. In this article we are assuming that you are running your webservice that has visibility to the DynamoDB container, the setup of the web service is out of scope for this article.

When using AWS SDK v2 for Golang things are done way differently then on version v1. In v1, you could provide an endpoint, a region and credentials that required for you to test locally. Just for reference, this is how you test in aws-sdk-go-v1:

        creds := credentials.NewEnvCredentials()
	_, err := creds.Get()
	if err != nil {
		return nil, err
	}
	sess, err := session.NewSession(&aws.Config{
		Region:      aws.String("us-east-1"),
		Endpoint:    aws.String("http://localhost:8000"),
		Credentials: creds},
	)
	if err != nil {
		return nil, err
	}
	// Create DynamoDB client
	svc := dynamodb.New(sess)

The endpoint value is whatever url you specified in your docker-compose file for you AWS DynamoDB instance.

Implement AWS SDK Go v2

Now to answer the question of this topic: Testing locally DynamoDB, how can we accomplish this? Compared to v1, we have to do things differently. In v2 you have to have a several awsconfig.LoadOptionFunc’s. You will need the WithRegion, WithEndpointResolver, and lastly for local testing WithCredentialsProvider. For v2, make sure you have an IAM Role that is able to talk to your ec2 instance or whatever infrastructure you are using to serve your app and the DynamoDB instance.

customResolver := aws.EndpointResolverFunc(func(service, region string) (aws.Endpoint, error) {
	if os.Getenv("APP_ENV") == "local" {
		return aws.Endpoint{
			URL: config.Dynamo.Endpoint,
		}, nil
	}
	// returning EndpointNotFoundError will allow the service to fallback to it's default resolution
	return aws.Endpoint{}, &aws.EndpointNotFoundError{}
})
var (
	cfg aws.Config
	err error
)
if os.Getenv("APP_ENV") == "local" {
	cfg, err = awsconfig.LoadDefaultConfig(context.TODO(), awsconfig.WithRegion("us-east-1"), awsconfig.WithEndpointResolver(customResolver), awsconfig.WithCredentialsProvider(credentials.StaticCredentialsProvider{
		Value: aws.Credentials{
			AccessKeyID: "dummy", SecretAccessKey: "dummy", SessionToken: "dummy",
		Source: "Hard-coded credentials; values are irrelevant for local DynamoDB",
		},
	}))
} else {
	cfg, err = awsconfig.LoadDefaultConfig(context.TODO(), awsconfig.WithRegion("us-east-1"), awsconfig.WithEndpointResolver(customResolver))
}	
if err != nil {
	panic(err)
}
svc := dynamodb.NewFromConfig(cfg)

In the code above, you will notice that I check for an environment variable to equal “local”. The reason for this is, in v2 you are discouraged from using AWS access keys. When you test locally, the container requires an AWS access key, therefore you can create dummy credentials to use when testing locally.

Thank you for taking the time to read this information. You can find other articles here.