OneMoreError
OneMoreError

Reputation: 7738

Set global secondary index name dynamically in dynamo db using environment variable spring boot

I am using derjust/spring-data-dynamodb library to interact with DynamoDB. I have defined a class Product as follows:

@DynamoDBTable(tableName = "product")
public class Product {

    @Id
    @NotNull
    @DynamoDBHashKey
    private String productId;

    @DynamoDBIndexHashKey(globalSecondaryIndexName = "product-category-gsi")
    private String categoryId;

    private double amount;

    // more fields, getters and setters    
}

I want to use the same code across multiple environments - dev, staging, prod. So, the table names would be dev-product, staging-product and prod-product.

The environment is available as an application property. I have configured the table name using the steps mentioned here: https://github.com/derjust/spring-data-dynamodb/wiki/Alter-table-name-during-runtime

@Configuration
@EnableDynamoDBRepositories(basePackages = "com.example.entity",dynamoDBMapperConfigRef = "dynamoDBMapperConfig")
public class DynamoDBConfiguration {

    @Value("${aws.region}")
    private String awsRegion;

    @Value("${env.name}")
    private String envName;

    @Bean
    public AmazonDynamoDB amazonDynamoDB() {
        return AmazonDynamoDBClientBuilder.standard()
            .withRegion(awsRegion)
            .build();
    }

    @Bean
    public DynamoDBMapperConfig.TableNameOverride tableNameOverrider() {
        return DynamoDBMapperConfig.TableNameOverride.withTableNameReplacement(envName + "-product");
    }

    @Bean
    public DynamoDBMapperConfig dynamoDBMapperConfig() {
        DynamoDBMapperConfig.Builder builder = new DynamoDBMapperConfig.Builder();
        builder.setTableNameOverride(tableNameOverrider());
        return new DynamoDBMapperConfig(DynamoDBMapperConfig.DEFAULT, builder.build());
    }
}

But how can I override the global secondary index name ? Currently, I have hardcoded it to "product-category-gsi".

I want to be able to set it dynamically like I am setting the table name to dev-product-category-gsi, staging-product-category-gsi and prod-product-category-gsi.

Upvotes: 4

Views: 2290

Answers (2)

Tarlog
Tarlog

Reputation: 10154

It's not really an answer to your question, but I still think it's worth mentioning, since it will solve your problem and will provide more stability to your application.

It's a good practice to have separated AWS accounts for different stages: dev, staging, production.

There are multiple reasons to do it:

  1. Fine grained access to the account (all devs have access to dev, but not to production)
  2. Separate billing (for example you may limit resources on dev accounts to limit your bills)
  3. Reuse of resource names (exactly your problem)
  4. Additional security on production (enable MFA)
  5. Each account has limits. Having multiple accounts keep these limits separated and also reduces the blast radius if these limits are reached.

Another solution: Given that you don't use ALL AWS regions, you can keep your stages in different regions. I cannot recommend it, but it's an option.

Upvotes: 0

Vikas
Vikas

Reputation: 7205

You can create a constant for globalSecondaryIndexName with environment name,

public class DynamoDBConstants {
    public static final String GLOBAL_SECONDARY_INDEXNAME = System.getProperty("env.name")+"product-category-gsi";
}

And use it as below,

@DynamoDBIndexHashKey(globalSecondaryIndexName = DynamoDBConstants.GLOBAL_SECONDARY_INDEXNAME)
private String categoryId;

Upvotes: 3

Related Questions