CtrlK
BlogDocsLog inGet started
Tessl Logo

giuseppe-trisciuoglio/developer-kit

Comprehensive developer toolkit providing reusable skills for Java/Spring Boot, TypeScript/NestJS/React/Next.js, Python, PHP, AWS CloudFormation, AI/RAG, DevOps, and more.

82

Quality

82%

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Risky

Do not use without reviewing

Validation failed for skills in this tile
One or more skills have errors that need to be fixed before they can move to Implementation and Discovery review.
Overview
Quality
Evals
Security
Files

spring-boot-integration.mdplugins/developer-kit-java/skills/aws-sdk-java-v2-dynamodb/references/

Spring Boot Integration Reference

This document provides detailed information about integrating DynamoDB with Spring Boot applications.

Configuration

Basic Configuration

@Configuration
public class DynamoDbConfiguration {

    @Bean
    @Profile("local")
    public DynamoDbClient dynamoDbClient() {
        return DynamoDbClient.builder()
            .region(Region.US_EAST_1)
            .build();
    }

    @Bean
    @Profile("prod")
    public DynamoDbClient dynamoDbClientProd(
            @Value("${aws.region}") String region,
            @Value("${aws.accessKeyId}") String accessKeyId,
            @Value("${aws.secretAccessKey}") String secretAccessKey) {

        return DynamoDbClient.builder()
            .region(Region.of(region))
            .credentialsProvider(StaticCredentialsProvider.create(
                AwsBasicCredentials.create(accessKeyId, secretAccessKey)))
            .build();
    }

    @Bean
    public DynamoDbEnhancedClient dynamoDbEnhancedClient(DynamoDbClient dynamoDbClient) {
        return DynamoDbEnhancedClient.builder()
            .dynamoDbClient(dynamoDbClient)
            .build();
    }
}

Properties Configuration

application-local.properties:

aws.region=us-east-1

application-prod.properties:

aws.region=us-east-1
aws.accessKeyId=${AWS_ACCESS_KEY_ID}
aws.secretAccessKey=${AWS_SECRET_ACCESS_KEY}

Repository Pattern Implementation

Base Repository Interface

public interface DynamoDbRepository<T> {
    void save(T entity);
    Optional<T> findById(Object partitionKey);
    Optional<T> findById(Object partitionKey, Object sortKey);
    void delete(Object partitionKey);
    void delete(Object partitionKey, Object sortKey);
    List<T> findAll();
    List<T> findAll(int limit);
    boolean existsById(Object partitionKey);
    boolean existsById(Object partitionKey, Object sortKey);
}

public interface CustomerRepository extends DynamoDbRepository<Customer> {
    List<Customer> findByEmail(String email);
    List<Customer> findByPointsGreaterThan(Integer minPoints);
}

Generic Repository Implementation

@Repository
public class GenericDynamoDbRepository<T> implements DynamoDbRepository<T> {

    private final DynamoDbTable<T> table;

    @SuppressWarnings("unchecked")
    public GenericDynamoDbRepository(DynamoDbEnhancedClient enhancedClient,
                                     Class<T> entityClass,
                                     String tableName) {
        this.table = enhancedClient.table(tableName, TableSchema.fromBean(entityClass));
    }

    @Override
    public void save(T entity) {
        table.putItem(entity);
    }

    @Override
    public Optional<T> findById(Object partitionKey) {
        Key key = Key.builder().partitionValue(partitionKey).build();
        return Optional.ofNullable(table.getItem(key));
    }

    @Override
    public Optional<T> findById(Object partitionKey, Object sortKey) {
        Key key = Key.builder()
            .partitionValue(partitionKey)
            .sortValue(sortKey)
            .build();
        return Optional.ofNullable(table.getItem(key));
    }

    @Override
    public void delete(Object partitionKey) {
        Key key = Key.builder().partitionValue(partitionKey).build();
        table.deleteItem(key);
    }

    @Override
    public List<T> findAll() {
        return table.scan().items().stream()
            .collect(Collectors.toList());
    }

    @Override
    public List<T> findAll(int limit) {
        return table.scan(ScanEnhancedRequest.builder().limit(limit).build())
            .items().stream()
            .collect(Collectors.toList());
    }
}

Specific Repository Implementation

@Repository
public class CustomerRepositoryImpl implements CustomerRepository {

    private final DynamoDbTable<Customer> customerTable;

    public CustomerRepositoryImpl(DynamoDbEnhancedClient enhancedClient) {
        this.customerTable = enhancedClient.table(
            "Customers",
            TableSchema.fromBean(Customer.class));
    }

    @Override
    public List<Customer> findByEmail(String email) {
        Expression filter = Expression.builder()
            .expression("email = :email")
            .putExpressionValue(":email", AttributeValue.builder().s(email).build())
            .build();

        return customerTable.scan(r -> r.filterExpression(filter))
            .items().stream()
            .collect(Collectors.toList());
    }

    @Override
    public List<Customer> findByPointsGreaterThan(Integer minPoints) {
        Expression filter = Expression.builder()
            .expression("points >= :minPoints")
            .putExpressionValue(":minPoints", AttributeValue.builder().n(minPoints.toString()).build())
            .build();

        return customerTable.scan(r -> r.filterExpression(filter))
            .items().stream()
            .collect(Collectors.toList());
    }
}

Service Layer Implementation

Service with Transaction Management

@Service
@Transactional
public class CustomerService {

    private final CustomerRepository customerRepository;
    private final OrderRepository orderRepository;
    private final DynamoDbEnhancedClient enhancedClient;

    public CustomerService(CustomerRepository customerRepository,
                          OrderRepository orderRepository,
                          DynamoDbEnhancedClient enhancedClient) {
        this.customerRepository = customerRepository;
        this.orderRepository = orderRepository;
        this.enhancedClient = enhancedClient;
    }

    public void createCustomerWithOrder(Customer customer, Order order) {
        // Use transaction for atomic operation
        enhancedClient.transactWriteItems(r -> r
            .addPutItem(getCustomerTable(), customer)
            .addPutItem(getOrderTable(), order));
    }

    private DynamoDbTable<Customer> getCustomerTable() {
        return enhancedClient.table("Customers", TableSchema.fromBean(Customer.class));
    }

    private DynamoDbTable<Order> getOrderTable() {
        return enhancedClient.table("Orders", TableSchema.fromBean(Order.class));
    }
}

Async Operations

@Service
public class AsyncCustomerService {

    private final DynamoDbEnhancedClient enhancedClient;

    public CompletableFuture<Void> saveCustomerAsync(Customer customer) {
        return CompletableFuture.runAsync(() -> {
            DynamoDbTable<Customer> table = enhancedClient.table(
                "Customers",
                TableSchema.fromBean(Customer.class));
            table.putItem(customer);
        });
    }

    public CompletableFuture<List<Customer>> findCustomersByPointsAsync(Integer minPoints) {
        return CompletableFuture.supplyAsync(() -> {
            Expression filter = Expression.builder()
                .expression("points >= :minPoints")
                .putExpressionValue(":minPoints", AttributeValue.builder().n(minPoints.toString()).build())
                .build();

            DynamoDbTable<Customer> table = enhancedClient.table(
                "Customers",
                TableSchema.fromBean(Customer.class));

            return table.scan(r -> r.filterExpression(filter))
                .items().stream()
                .collect(Collectors.toList());
        });
    }
}

Testing with LocalStack

Test Configuration

@TestConfiguration
@ContextConfiguration(classes = {LocalStackDynamoDbConfig.class})
public class DynamoDbTestConfig {

    @Bean
    public DynamoDbClient dynamoDbClient() {
        return LocalStackDynamoDbConfig.dynamoDbClient();
    }

    @Bean
    public DynamoDbEnhancedClient dynamoDbEnhancedClient() {
        return DynamoDbEnhancedClient.builder()
            .dynamoDbClient(dynamoDbClient())
            .build();
    }
}

@SpringBootTest(classes = {DynamoDbTestConfig.class})
@Import(DynamoDbTestConfig.class)
public class CustomerRepositoryIntegrationTest {

    @Autowired
    private DynamoDbEnhancedClient enhancedClient;

    @BeforeEach
    void setUp() {
        // Clean up test data
        clearTestData();
    }

    @Test
    void testCustomerOperations() {
        // Test implementation
    }
}

LocalStack Container Setup

public class LocalStackDynamoDbConfig {

    @Container
    static LocalStackContainer localstack = new LocalStackContainer(
        DockerImageName.parse("localstack/localstack:3.0"))
        .withServices(LocalStackContainer.Service.DYNAMODB);

    @Bean
    @DynamicPropertySource
    public static void configureProperties(DynamicPropertyRegistry registry) {
        registry.add("aws.region", () -> Region.US_EAST_1.toString());
        registry.add("aws.accessKeyId", () -> localstack.getAccessKey());
        registry.add("aws.secretAccessKey", () -> localstack.getSecretKey());
        registry.add("aws.endpoint",
            () -> localstack.getEndpointOverride(LocalStackContainer.Service.DYNAMODB).toString());
    }

    @Bean
    public DynamoDbClient dynamoDbClient(
            @Value("${aws.region}") String region,
            @Value("${aws.accessKeyId}") String accessKeyId,
            @Value("${aws.secretAccessKey}") String secretAccessKey,
            @Value("${aws.endpoint}") String endpoint) {

        return DynamoDbClient.builder()
            .region(Region.of(region))
            .endpointOverride(URI.create(endpoint))
            .credentialsProvider(StaticCredentialsProvider.create(
                AwsBasicCredentials.create(accessKeyId, secretAccessKey)))
            .build();
    }
}

Health Check Integration

Custom Health Indicator

@Component
public class DynamoDbHealthIndicator implements HealthIndicator {

    private final DynamoDbClient dynamoDbClient;

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

    @Override
    public Health health() {
        try {
            dynamoDbClient.listTables();
            return Health.up()
                .withDetail("region", dynamoDbClient.serviceClientConfiguration().region())
                .build();
        } catch (Exception e) {
            return Health.down()
                .withException(e)
                .build();
        }
    }
}

Metrics Collection

Micrometer Integration

@Component
public class DynamoDbMetricsCollector {

    private final DynamoDbClient dynamoDbClient;
    private final MeterRegistry meterRegistry;

    @EventListener
    public void handleDynamoDbOperation(DynamoDbOperationEvent event) {
        Timer.Sample sample = Timer.start();
        sample.stop(Timer.builder("dynamodb.operation")
            .tag("operation", event.getOperation())
            .tag("table", event.getTable())
            .register(meterRegistry));
    }
}

public class DynamoDbOperationEvent {
    private String operation;
    private String table;
    private long duration;

    // Getters and setters
}

plugins

developer-kit-java

skills

README.md

tile.json