Search code examples
springrestspring-mvcspring-bootspring-restcontroller

Control @RestController availability programmatically


Is it possible to control a @RestController programmatically to enable it or disable it? I don't want to just write code in each @RequestMapping method to do some kind of if (!enabled) { return 404Exception; }

I've seen this question but that works only at startup time. What I need is really something that would allow me to enable or disable the controller multiple times.

I've thought of different ways but don't know which are doable in spring.

  1. Actually control the container (jetty in my case) so requests to that particular endpoint are disabled
  2. Somehow control RequestMappingHandlerMapping since it seems to be that class that does the mapping between urls and controllers
  3. control the lifecycle of the @RestController component so that i can create it and destroy it at will, but then i'm not sure how to trigger the mapping to the endpoint

Solution

  • If the end result is that you want to respond with a 404 when you decide that a specific endpoint should be disabled then you could write an interceptor which checks whether your enabled condition is false and, if so, sets the response accordingly.

    For example:

    @Component
    public class ConditionalRejectionInterceptor extends HandlerInterceptorAdapter {
    
        @Override
        public boolean preHandle(HttpServletRequest request,
                HttpServletResponse response, Object handler) throws Exception {
            String requestUri = request.getRequestURI();
            if (shouldReject(requestUri)) {
                response.setStatus(HttpStatus.NOT_FOUND.value());
                return false;
            }
            return super.preHandle(request, response, handler);
        }
    
        private boolean shouldReject(String requestUri) {
            // presumably you have some mechanism of inferring or discovering whether 
            // the endpoint represented by requestUri should be allowed or disallowed
            return ...;
        }
    }
    

    In Spring Boot, registering your own interceptor just involves implementing a WebMvcConfigurerAdapter. For example:

    @Configuration
    public class CustomWebMvcConfigurer extends WebMvcConfigurerAdapter {
    
      @Autowired 
      private HandlerInterceptor conditionalRejectionInterceptor;
    
      @Override
      public void addInterceptors(InterceptorRegistry registry) {
        // you can use .addPathPatterns(...) here to limit this interceptor to specific endpoints
        // this could be used to replace any 'conditional on the value of requestUri' code in the interceptor
        registry.addInterceptor(conditionalRejectionInterceptor);
      }
    }