

# DAX SDK for Go
<a name="DAX.client.run-application-go-2"></a>

Follow this procedure to run the Amazon DynamoDB Accelerator (DAX) SDK for Go sample application on your Amazon EC2 instance.

**To run the SDK for Go sample for DAX**

1. Set up the SDK for Go on your Amazon EC2 instance:

   1. Install the Go programming language (`Golang`).

      ```
      sudo yum install -y golang
      ```

   1. Test that Golang is installed and running correctly.

      ```
      go version
      ```

      A message like this should appear.

      ```
      go version go1.23.4 linux/amd64
      ```

1. Install the sample Golang application.

   ```
   go get github.com/aws-samples/sample-aws-dax-go-v2
   ```

1. Run the following Golang programs. The first program creates a DynamoDB table named `TryDaxGoTable`. The second program writes data to the table.

   ```
   go run ~/go/pkg/mod/github.com/aws-samples/sample-aws-dax-go-v2@v1.0.0/try_dax.go -service dynamodb -command create-table
   ```

   ```
   go run ~/go/pkg/mod/github.com/aws-samples/sample-aws-dax-go-v2@v1.0.0/try_dax.go -service dynamodb -command put-item
   ```

1. Run the following Golang programs.

   ```
   go run ~/go/pkg/mod/github.com/aws-samples/sample-aws-dax-go-v2@v1.0.0/try_dax.go -service dynamodb -command get-item
   ```

   ```
   go run ~/go/pkg/mod/github.com/aws-samples/sample-aws-dax-go-v2@v1.0.0/try_dax.go -service dynamodb -command query
   ```

   ```
   go run ~/go/pkg/mod/github.com/aws-samples/sample-aws-dax-go-v2@v1.0.0/try_dax.go -service dynamodb -command scan
   ```

   Take note of the timing information—the number of milliseconds required for the `GetItem`, `Query`, and `Scan` tests.

1. In the previous step, you ran the programs against the DynamoDB endpoint. Now, run the programs again, but this time, the `GetItem`, `Query`, and `Scan` operations are processed by your DAX cluster.

   To determine the endpoint for your DAX cluster, choose one of the following:
   + **Using the DynamoDB console** — Choose your DAX cluster. The cluster endpoint is shown on the console, as in the following example.

     ```
     dax://my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com
     ```
   + **Using the AWS CLI** — Enter the following command.

     ```
     aws dax describe-clusters --query "Clusters[*].ClusterDiscoveryEndpoint"
     ```

     The cluster endpoint is shown in the output, as in the following example.

     ```
     {
         "Address": "my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com",
         "Port": 8111,
         "URL": "dax://my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com"
     }
     ```

   Now run the programs again, but this time, specify the cluster endpoint as a command line parameter.

   ```
   go run ~/go/pkg/mod/github.com/aws-samples/sample-aws-dax-go-v2@v1.0.0/try_dax.go -service dax -command get-item -endpoint my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com:8111
   ```

   ```
   go run ~/go/pkg/mod/github.com/aws-samples/sample-aws-dax-go-v2@v1.0.0/try_dax.go -service dax -command query -endpoint my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com:8111
   ```

   ```
   go run ~/go/pkg/mod/github.com/aws-samples/sample-aws-dax-go-v2@v1.0.0/try_dax.go -service dax -command scan -endpoint my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com:8111
   ```

   ```
   go run ~/go/pkg/mod/github.com/aws-samples/sample-aws-dax-go-v2@v1.0.0/try_dax.go -service dax -command paginated-scan -endpoint my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com:8111
   ```

   ```
   go run ~/go/pkg/mod/github.com/aws-samples/sample-aws-dax-go-v2@v1.0.0/try_dax.go -service dax -command paginated-query -endpoint my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com:8111
   ```

   ```
   go run ~/go/pkg/mod/github.com/aws-samples/sample-aws-dax-go-v2@v1.0.0/try_dax.go -service dax -command paginated-batch-get -endpoint my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com:8111
   ```

   Look at the rest of the output, and take note of the timing information. The elapsed times for `GetItem`, `Query`, and `Scan` should be significantly lower with DAX than with DynamoDB.

1. Run the following Golang program to delete `TryDaxGoTable`.

   ```
   go run ~/go/pkg/mod/github.com/aws-samples/sample-aws-dax-go-v2@v1.0.0/try_dax.go -service dynamodb -command delete-table
   ```

## Features not in parity with AWS SDK for Go V2
<a name="DAX.client.run-application-go-features-not-in-parity"></a>

Middleware Stack – DAX Go V2 doesn’t support the use of Middleware Stacks through APIoptions. For more information, see [Customizing the AWS SDK for Go v2 Client Requests with Middleware](https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/middleware.html#:~:text=You%20can%20customize%20AWS%20SDK,step's%20input%20and%20output%20types).

Example:

```
// Custom middleware implementation
type customSerializeMiddleware struct{}
// ID returns the identifier for the middleware
func (m *customSerializeMiddleware) ID() string {
    return "CustomMiddleware"
}
// HandleSerialize implements the serialize middleware handler
func (m *customSerializeMiddleware) HandleSerialize(
    ctx context.Context,
    in middleware.SerializeInput,
    next middleware.SerializeHandler,
) (
    out middleware.SerializeOutput,
    metadata middleware.Metadata,
    err error,
) {
    // Add your custom logic here before the request is serialized
    fmt.Printf("Executing custom middleware for request: %v\n", in)
    // Call the next handler in the middleware chain
    return next.HandleSerialize(ctx, in)
}

func executeGetItem(ctx context.Context) error {
    client, err := initItemClient(ctx)
    if err != nil {
        os.Stderr.WriteString(fmt.Sprintf("failed to initialize client: %v\n", err))
        return err
    }

    st := time.Now()
    for c := 0; c < iterations; c++ {
        for i := 0; i < pkMax; i++ {
            for j := 0; j < skMax; j++ {
                // Create key using attributevalue.Marshal for type safety
                pk, err := attributevalue.Marshal(fmt.Sprintf("%s_%d", keyPrefix, i))
                if err != nil {
                    return fmt.Errorf("error marshaling pk: %v", err)
                }
                sk, err := attributevalue.Marshal(fmt.Sprintf("%d", j))
                if err != nil {
                    return fmt.Errorf("error marshaling sk: %v", err)
                }
                key := map[string]types.AttributeValue{
                    "pk": pk,
                    "sk": sk,
                }
                in := &dynamodb.GetItemInput{
                    TableName: aws.String(table),
                    Key:       key,
                }

                // Custom middleware option
                customMiddleware := func(o *dynamodb.Options) {
                    o.APIOptions = append(o.APIOptions, func(stack *middleware.Stack) error {
                        // Add custom middleware to the stack
                        return stack.Serialize.Add(&customSerializeMiddleware{}, middleware.After)
                    })
                }

                // Apply options to the GetItem call
                out, err := client.GetItem(ctx, in, customMiddleware)
                if err != nil {
                    return err
                }
                writeVerbose(out)
            }
        }
    }
    d := time.Since(st)
    os.Stdout.WriteString(fmt.Sprintf("Total Time: %v, Avg Time: %v\n", d, d/iterations))
    return nil
}
```

Output:

```
failed to execute command: custom middleware through APIOptions is not supported in DAX client
exit status 1
```

# Default client configuration for Go
<a name="DAX-client-config-Go"></a>

This guide will walk you through the configuration options that allow you to fine-tune your DAX client's performance, connection management, and logging behavior. By understanding the default settings and how to customize them, you can optimize your Go application's interaction with DAX.

**Topics**
+ [DAX Go SDK Client Defaults](#DAX-client-config-Go-sdk-client-defaults)
+ [Client creation](#DAX-client-config-Go-client-creation)

## DAX Go SDK Client Defaults
<a name="DAX-client-config-Go-sdk-client-defaults"></a>


| Parameter | Type | Description | 
| --- | --- | --- | 
|  `Region` required  |  `string`  |  The AWS Region to use for the DAX client (example- 'us-east-1'). This is a required parameter if not provided through the environment.  | 
|  `HostPorts` required  |  `[] string`  |  List of DAX cluster endpoints to which SDK connects.  For example: Non-Encrypted – dax://my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com Encrypted – daxs://my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com  | 
|  `MaxPendingConnectionsPerHost` default 10  |  `number`  | Number of concurrent connection attempts. (Connections can be in the process of being established concurrently.)  | 
|  `ClusterUpdateThreshold` default 125 \$1 time.Millisecond  |  `time.Duration`  | The minimum time that must elapse between cluster refreshes.  | 
|  `ClusterUpdateInterval` default 4 \$1 time.Second  |  `time.Duration`  | The interval at which the client will automatically refresh the DAX cluster information.  | 
|  `IdleConnectionsReapDelay` default 30 \$1 time.Second  |  `time.Duration`  | The interval at which the client will close idle connections in the DAX client.  | 
|  `ClientHealthCheckInterval` default 5 \$1 time.Second  |  `time.Duration`  | The interval at which the client will perform health checks on the DAX cluster endpoints.  | 
|  `Credentials` default  |  `aws.CredentialsProvider`  | The AWS credentials used by the DAX client to authenticate requests to the DAX service. See [Credentials and Credential Providers](https://docs.aws.amazon.com/sdk-for-go/v2/developer-guide/migrate-gosdk.html#credentials--credential-providers).  | 
|  `DialContext` default  |  `func`  | A custom function used by the DAX client to establish connections to the DAX cluster.  | 
|  `SkipHostnameVerification` default false  |  bool  |  Skip hostname verification of TLS connections. This setting only affects encrypted clusters. When set to True, it disables hostname verification. Disabling verification means you can't authenticate the identity of the cluster you're connecting to, which poses security risks. By default, hostname verification is enabled.  | 
|  `RouteManagerEnabled` default false  |  `bool`  | This flag is used to remove routes facing network errors.  | 
|  `RequestTimeout` default 60 \$1 time.Second  |  `time.Duration`  | This defines the maximum time the client will wait for a response from DAX. Priority: Context timeout (if set) > `RequestTimmeout` (if set) > Default 60s `RequestTimeout`.  | 
|  `WriteRetries` default 2  |  `number`  |  The number of retries to attempt for write requests that fail.  | 
|  `ReadRetries` default 2  |  `number`  | The number of retries to attempt for read requests that fail.  | 
|  `RetryDelay` default 0  |  `time.Duration`  | The delay for non-throttled errors (in seconds) for retry attempts when a request fails.  | 
|  `Logger` optional  |  `logging.Logger`  | Logger is an interface for logging entries at certain classifications.  | 
|  `LogLevel` default utils.LogOff  |  `number`  | This loglevel is defined for DAX only. It can be imported using [github.com/aws/aws-dax-go-v2/tree/main/dax/utils](https://github.com/aws/aws-dax-go-v2/tree/main/dax/utils).  <pre>const (    <br /> LogOff LogLevelType = 0   <br /> LogDebug LogLevelType = 1   <br /> LogDebugWithRequestRetries<br /> LogLevelType = 2<br />)</pre>  | 

**Note**  
For `time.Duration`, the default unit is nanosecond. If we don’t specify any unit for any parameter then it will consider that as nano seconds: `daxCfg.ClusterUpdateInterval = 10` means 10 nano seconds. (`daxCfg.ClusterUpdateInterval = 10 * time.Millisecond` means 10 milliseconds).

## Client creation
<a name="DAX-client-config-Go-client-creation"></a>

**To create a DAX client:**
+ Create DAX config, then create DAX client using DAX config. Using this, you can overwrite a DAX configuration if required.

  ```
  import (
  "github.com/aws/aws-dax-go-v2/dax/utils"
  "github.com/aws/aws-dax-go-v2/dax"
  )
  
  // Non - Encrypted : 'dax://my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com'.
  // Encrypted : daxs://my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com'.
  
  config := dax.DefaultConfig()
  config.HostPorts = []string{endpoint}
  config.Region = region
  config.LogLevel = utils.LogDebug
  daxClient, err := dax.New(config)
  ```

# Migrating to DAX Go SDK V2
<a name="DAX.client.run-application-go-migrating"></a>

This migration guide will help you transition your existing DAX Go applications.

## V1 DAX Go SDK usage
<a name="DAX.client.run-application-go-V1-usage"></a>

```
package main

import (
    "fmt"
    "os"

    "github.com/aws/aws-dax-go/dax"
    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/dynamodb"
)

func main() {
    region := "us-west-2"
    endpoint := "dax://my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com"
    
    // Create session
    sess, err := session.NewSession(&aws.Config{
        Region: aws.String(region),
    })
    if err != nil {
        fmt.Printf("Failed to create session: %v\n", err)
        os.Exit(1)
    }
    
    // Configure DAX client
    cfg := dax.DefaultConfig()
    cfg.HostPorts = []string{endpoint} 
    cfg.Region = region

    // Create DAX client
    daxClient, err := dax.New(cfg)
    if err != nil {
        fmt.Printf("Failed to create DAX client: %v\n", err)
        os.Exit(1)
    }
    defer daxClient.Close() // Don't forget to close the client

    // Create GetItem input
    input := &dynamodb.GetItemInput{
        TableName: aws.String("TryDaxTable"),
        Key: map[string]*dynamodb.AttributeValue{
            "pk": {
                N: aws.String("1"),
            },
            "sk": {
                N: aws.String("1"),
            },
        },
    }

    // Make the GetItem call
    result, err := daxClient.GetItem(input)
    if err != nil {
        fmt.Printf("Failed to get item: %v\n", err)
        os.Exit(1)
    }

    // Print the result
    fmt.Printf("GetItem succeeded: %+v\n", result)
}
```

## V2 DAX Go SDK usage
<a name="DAX.client.run-application-go-V2-usage"></a>

```
package main

import (
    "context"
    "fmt"
    "os"

    "github.com/aws/aws-dax-go-v2/dax"
    "github.com/aws/aws-sdk-go-v2/config"
    "github.com/aws/aws-sdk-go-v2/service/dynamodb"
    "github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
    "github.com/aws/aws-sdk-go-v2/feature/dynamodb/attributevalue"
    "github.com/aws/aws-sdk-go-v2/aws"
)

func main() {
    ctx := context.Background()
    region := "us-west-2"
    endpoint := "dax://my-cluster.l6fzcv.dax-clusters.us-east-1.amazonaws.com"
   
    // Create DAX config
    config := dax.DefaultConfig()
    // Specify Endpoint and Region
    config.HostPorts = []string{endpoint}
    config.Region = region
    // Enabling logging
    config.LogLevel = utils.LogDebug
    // Create DAX client
    daxClient, err := dax.New(config) 
    if err != nil {
        fmt.Printf("Failed to create DAX client: %v\n", err)
        os.Exit(1)
    }
    defer daxClient.Close() // Don't forget to close the client

    // Create key using attributevalue.Marshal for type safety
    pk, err := attributevalue.Marshal(fmt.Sprintf("%s_%d", keyPrefix, i))
    if err != nil {
        return fmt.Errorf("error marshaling pk: %v", err)
    }
    sk, err := attributevalue.Marshal(fmt.Sprintf("%d", j))
    if err != nil {
        return fmt.Errorf("error marshaling sk: %v", err)
    }
                
    // Create GetItem input
    input := &dynamodb.GetItemInput{
        TableName: aws.String("TryDaxTable"),
        Key: map[string]types.AttributeValue{
             "pk": pk,
             "sk": sk,
        },
    }

    // Make the GetItem call
    result, err := daxClient.GetItem(ctx, input)
    if err != nil {
        fmt.Printf("Failed to get item: %v\n", err)
        os.Exit(1)
    }

    // Print the result
    fmt.Printf("GetItem succeeded: %+v\n", result)
}
```

For more API usage details, see [AWS samples](https://github.com/aws-samples/sample-aws-dax-go-v2).