= DynamoDB Integration

https://aws.amazon.com/dynamodb/[DynamoDB] is a fully managed serverless key/value Nosql database designed for high performance.
A Spring Boot starter is provided to auto-configure DynamoDb integration beans.

Maven coordinates, using <<index.adoc#bill-of-materials, Spring Cloud AWS BOM>>:

[source,xml]
----
<dependency>
    <groupId>io.awspring.cloud</groupId>
    <artifactId>spring-cloud-aws-starter-dynamodb</artifactId>
</dependency>
----

DynamoDB integration will only provide autoconfiguration and simple `DynamoDbOperations` which can be used to communicate with DynamoDb, build repositories and so on...

== DynamoDbOperations

The starter automatically configures and registers a `DynamoDbOperations` bean providing higher level abstractions for working with DynamoDb.
`DynamoDbTemplate` - a default `DynamoDbOperations` implementation - being built on top of `DynamoDbEnhancedClient` uses annotations provided by AWS.
The list of supported annotations can be found https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/enhanced/dynamodb/mapper/annotations/package-summary.html[here].

`DynamoDbEnchancedClient` supports a programming model similar to JPA - where a class is turned into an entity through applying certain annotations:

[source,java]
----
import java.util.UUID;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;

@DynamoDbBean
public class Person {
	private UUID id;
	private String name;
	private String lastName;

	@DynamoDbPartitionKey
	public UUID getId() {
		return id;
	}

    ...
}
----

`DynamoDbTemplate` provides methods to perform typical CRUD operations on such entities, plus it adds convenience methods for querying DynamoDb:

[source,java]
----

import io.awspring.cloud.dynamodb.DynamoDbTemplate;

...
@Autowired
DynamoDbTemplate dynamoDbTemplate;
...
Person person = new Person(...)
dynamoDbTemplate.save(person);
----

=== Resolving Table Name

To resolve a table name for an entity, `DynamoDbTemplate` uses a bean of type `DynamoDbTableNameResolver`. The default implementation turns an entity class name into its snake case representation with the possibility of using a table name prefix (optional). Specify the `spring.cloud.aws.dynamodb.table-prefix` to provide a table name prefix. The prefix is prepended to the table name. For example, if `spring.cloud.aws.dynamodb.table-prefix` is configured as `foo_` and the entity class is `Person`, then the default implementation resolves the table name as `foo_person`. However if you do not specify `spring.cloud.aws.dynamodb.table-prefix`, the table name will be resolved as `person`.

To use a custom implementation, declare a bean of type `DynamoDbTableNameResolver` and it will get injected into `DynamoDbTemplate` automatically during auto-configuration.

=== Resolving Table Schema

To resolve a table schema for an entity, `DynamoDbTemplate` uses a bean of type `DynamoDbTableSchemaResolver`. The default implementation caches `TableSchema` objects in internal map.
To use custom implementation, declare a bean of type `DynamoDbTableSchemaResolver` and it will get injected into `DynamoDbTemplate` automatically during auto-configuration.
To register a custom table schema for a DynamoDB entity a bean of type `TableSchema`  should be created:
[source, java]
----
@Configuration
public class MyTableSchemaConfiguration {

    @Bean
    public TableSchema<MyEntity> myEntityTableSchema() {
        // create and return a TableSchema object for the MyEntity class
    }
}
----

IMPORTANT: Because of classloader related https://github.com/aws/aws-sdk-java-v2/issues/2604[issue] in AWS SDK DynamoDB Enhanced client, to use Spring Cloud AWS DynamoDB module together with Spring Boot DevTools you must create a custom table schema resolver and define schema using `StaticTableSchema`.

== Using DynamoDb Client

Autoconfiguration automatically configures `DynamoDbClient` which can be used for low level api calls and `DynamoDbEnhancedClient` if `DynamoDbOperations` are not enough.

If autoconfigured `DynamoDbClient` or `DynamoDbEnhancedClient` bean configuration does not meet your needs, it can be replaced by creating your custom bean.

[source,java]
----
import java.util.Collections;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import software.amazon.awssdk.services.dynamodb.model.DeleteItemRequest;

public class DynamoDbService {
	private final DynamoDbClient dynamoDbClient;

	public DynamoDbService(DynamoDbClient dynamoDbClient) {
		this.dynamoDbClient = dynamoDbClient;
	}

	void deletePerson(String uuid) {
		dynamoDbClient.deleteItem(DeleteItemRequest.builder().key(Collections.singletonMap("uuid", AttributeValue.builder().s(uuid).build())).build());
	}
}
----

== Using DynamoDB Accelerator

The starter automatically configures and registers an `software.amazon.dax.ClusterDaxClient` bean if it finds the following is added to the project:

[source,xml]
----
<dependency>
	<groupId>software.amazon.dax</groupId>
	<artifactId>amazon-dax-client</artifactId>
</dependency>
----

== Configuration

The Spring Boot Starter for DynamoDb provides the following configuration options:

[cols="3,3,1,1"]
|===
| Name | Description | Required | Default value
| `spring.cloud.aws.dynamodb.enabled` | Enables the DynamoDb integration. | No | `true`
| `spring.cloud.aws.dynamodb.endpoint` | Configures endpoint used by `DynamoDbClient`. | No |
| `spring.cloud.aws.dynamodb.region` | Configures region used by `DynamoDbClient`. | No |
| `spring.cloud.aws.dynamodb.table-prefix` | Table name prefix used by the default `DynamoDbTableNameResolver` implementation. | No |

| `spring.cloud.aws.dynamodb.dax.idle-timeout-millis` |Timeout for idle connections with the DAX cluster. | No | `30000`
| `spring.cloud.aws.dynamodb.dax.url` | DAX cluster endpoint. | Yes |
| `spring.cloud.aws.dynamodb.dax.connection-ttl-millis` |  Connection time to live. | No | `0`
| `spring.cloud.aws.dynamodb.dax.connect-timeout-millis` | Connection timeout | No | `1000`
| `spring.cloud.aws.dynamodb.dax.request-timeout-millis` | Request timeout for connections with the DAX cluster. | No | `1000`
| `spring.cloud.aws.dynamodb.dax.write-retries` | Number of times to retry writes, initial try is not counted. | No | `2`
| `spring.cloud.aws.dynamodb.dax.read-retries` | Number of times to retry reads, initial try is not counted. | No | `2`
| `spring.cloud.aws.dynamodb.dax.cluster-update-interval-millis` | Interval between polling of cluster members for membership changes. | No | `4000`
| `spring.cloud.aws.dynamodb.dax.endpoint-refresh-timeout-millis` | Timeout for endpoint refresh. | No | `6000`
| `spring.cloud.aws.dynamodb.dax.max-concurrency` | Maximum number of concurrent requests. | No | 1000
| `spring.cloud.aws.dynamodb.dax.max-pending-connection-acquires` | Maximum number of pending Connections to acquire. | No | 10000
| `spring.cloud.aws.dynamodb.dax.skip-host-name-verification` | Skips hostname verification in url. | No |
|===

== IAM Permissions

Since it depends on how you will use DynamoDb integration providing a list of IAM policies would be pointless since least privilege model should be used.
To check what IAM policies DynamoDb uses and see which ones you should use please check https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/using-identity-based-policies.html[IAM policies]
