23/03/2025 - AWS, DOCKER, GO
In this example we are going to use AWS DynamoDB Local docker image to spin up a DynamoDB instance then create table and populate it using JSON files. Finally we will visualise it using NoSQL Workbench and write a very basic Go application to fetch an item.
├── Makefile
├── fixture.json
├── main.go
├── storage
│ ├── dynamodb.go
│ └── model.go
└── table.json
TABLE=blog
URL=http://localhost:8000
.PHONY: db-up
db-up:
docker run --rm --publish 8000:8000 --name ${TABLE}-dynamodb amazon/dynamodb-local:latest -jar DynamoDBLocal.jar -sharedDb -cors "*"
.PHONY: db-create
db-create:
aws dynamodb --endpoint-url ${URL} create-table --cli-input-json file://table.json || true
aws dynamodb --endpoint-url ${URL} batch-write-item --request-items file://fixture.json
.PHONY: db-show
db-show:
aws dynamodb --endpoint-url ${URL} scan --table-name ${TABLE}
.PHONY: db-del
db-del:
aws dynamodb --endpoint-url ${URL} delete-table --table-name ${TABLE}
{
"TableName": "blog",
"AttributeDefinitions": [
{
"AttributeName": "_part_key",
"AttributeType": "S"
}
],
"KeySchema": [
{
"AttributeName": "_part_key",
"KeyType": "HASH"
}
],
"ProvisionedThroughput": {
"ReadCapacityUnits": 5,
"WriteCapacityUnits": 5
}
}
{
"blog": [
{
"PutRequest": {
"Item": {
"_part_key": {
"S": "id#fe622e2a-12f3-40b3-995b-2f28a63c6e42"
},
"_model": {
"S": "user"
},
"id": {
"S": "fe622e2a-12f3-40b3-995b-2f28a63c6e42"
},
"name": {
"S": "Al Pacino"
}
}
}
},
{
"PutRequest": {
"Item": {
"_part_key": {
"S": "id#6f063093-dc46-4864-8fd8-67135e7b5bae"
},
"_model": {
"S": "user"
},
"id": {
"S": "6f063093-dc46-4864-8fd8-67135e7b5bae"
},
"name": {
"S": "Robert De Niro"
}
}
}
}
]
}
package main
import (
"context"
"fmt"
"log"
"docker/storage"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
)
func main() {
ctx := context.Background()
awsConfig, err := config.LoadDefaultConfig(ctx, func(o *config.LoadOptions) error {
o.Region = "eu-west-1"
return nil
})
if err != nil {
log.Fatalln(err)
}
awsDynamo := dynamodb.NewFromConfig(awsConfig, func(o *dynamodb.Options) {
o.BaseEndpoint = aws.String("http://localhost:8000")
})
repository := storage.DynamoDB{
Client: awsDynamo,
Table: "blog",
}
user, err := repository.FindUserByID(ctx, "fe622e2a-12f3-40b3-995b-2f28a63c6e42")
if err != nil {
log.Fatalln(err)
}
fmt.Printf("%+v\n", user)
}
package storage
type Item struct {
PartKey string `dynamodbav:"_part_key"`
Model string `dynamodbav:"_model"`
}
func (Item) AttrTablePartKey() string {
return "_part_key"
}
type User struct {
Item
ID string `dynamodbav:"id"`
Name string `dynamodbav:"name"`
}
func (u *User) Build() {
u.Item = Item{
PartKey: "id#" + u.ID,
Model: "user",
}
}
package storage
import (
"context"
"fmt"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue"
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
)
type DynamoDB struct {
Client *dynamodb.Client
Table string
}
func (d DynamoDB) FindUserByID(ctx context.Context, id string) (User, error) {
model := User{
ID: id,
}
model.Build()
res, err := d.Client.GetItem(ctx, &dynamodb.GetItemInput{
TableName: aws.String(d.Table),
Key: map[string]types.AttributeValue{
model.Item.AttrTablePartKey(): &types.AttributeValueMemberS{Value: model.Item.PartKey},
},
})
if err != nil {
return User{}, fmt.Errorf("get item: %s", err.Error())
}
if res.Item == nil {
return User{}, nil
}
if err := attributevalue.UnmarshalMap(res.Item, &model); err != nil {
return User{}, fmt.Errorf("unmarshal map: %s", err.Error())
}
return model, nil
}
$ cat .aws/config
[default]
region = eu-west-1
output = json
$ cat .aws/credentials
[default]
aws_access_key_id = none
aws_secret_access_key = none
$ make db-up
Initializing DynamoDB Local with the following configuration:
Port: 8000
InMemory: false
Version: 2.6.0
DbPath: null
SharedDb: true
shouldDelayTransientStatuses: false
CorsParams: *
$ make db-create
Click "Add connection" button. Go to "DynamoDB local" tab. Give it a meaningful connection name then use localhost
for hostname and 8000
as port.
$ go run -race main.go
{Item:{TablePartKey:id#fe622e2a-12f3-40b3-995b-2f28a63c6e42 Model:user} ID:fe622e2a-12f3-40b3-995b-2f28a63c6e42 Name:Al Pacino}