Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make a REST controller conditional on the environment?

We have a use case where we want a set of endpoints to be enabled in every environment except the production environment. Rather than implementing a custom security implementation for this use case, our idea was to use a variation of Spring's Conditional annotation to only enable the controller in non-production environments.

Our initial attempt was to use @ConditionalOnExpression by injecting a dynamic system property that specifies the type of environment (eg. dev, test, prod, etc.) and to match that property against a regular expression, but we have not been able to get the SpEL expressions to resolve properly in a way that suits our needs.

@RestController
@ConditionalOnExpression("${property.name} matches ^((?!prod).)*$")
public class TestDataController

We have also considered using @ConditionalOnProperty, but there seems to be no way to allow this property to accept multiple valid values.

@RestController
@ConditionalOnProperty(
        value = "property.name",
        havingValue = "value1" or "value2",
        matchIfMissing = true)
public class TestDataController

Our last attempt was to write a custom class extending Spring's Conditional class to suit our needs. This works for now, but it is relying on Java file I/O, which we would like to avoid if possible.

Any ideas?

UPDATE 29 May 19

We were able to use the following solution to solve our problem:

  1. Define a custom conditional in the following way:
public class NotInProductionCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        final String env = context.getEnvironment().getProperty("property.name");
        if (env == null || env.isEmpty()) {
            return true;
        }
        return !env.contains("prod");
    }
}
  1. Use the custom condition on our controller:
@RestController
@Conditional(NotInProductionCondition.class)
public class TestDataController
like image 563
mgzwarrior Avatar asked May 28 '19 19:05

mgzwarrior


1 Answers

You can use @Profile annotation to instantiate a bean depending on a profile set in your environment.

@RestController
@Profile("!prod")
class MyController {
  ...
}

If you don't use profiles in your environment you most likely using some type of environment variable to specify the environment name, I suppose. You can make it a spring profile like this

spring.profiles.active = ${environmentName}
like image 137
arseniyandru Avatar answered Sep 28 '22 19:09

arseniyandru