3

Is there a way to add validation to feign clients on the request parameters.

For example:

@FeignClient
public interface ZipCodeClient {
    @GetMapping("/zipcodes/{zipCode}")
    Optional<ZipCodeView> findByZipCode(@PathVariable("zipCode") String zipCode);
}

It would be nice to verify that zipcode is not empty and is of certain length etc, before sending the HTTP call to the server.

postalservice14
  • 2,515
  • 4
  • 25
  • 33

2 Answers2

1

If your validations are simple, apply to only headers and query string parameters, you can use a RequestInterceptor for this, as it provides you the opportunity to review the RequestTemplate before it is sent to the Client.

public class ValidatingRequestInterceptor implements RequestInterceptor {
   public void apply(RequestTemplate requestTemplate) {
      // use the methods on the request template to check the query and values.
      // throw an exception if the request is not valid.
   }
}

If you need to validate the request body, you can use a custom Encoder

public class ValidatingEncoder implements Encoder {
   public void encode(Object object, Type type, RequestTemplate template) {
      // validate the object
      // throw an exception if the request is not valid.
   }
}

Lastly, if you want to validate individual parameters, you can provide a custom Expander for the parameter and validate it there. You can look at this answer for a complete explanation on how to create a custom expander that can work with Spring Cloud.

How to custom @FeignClient Expander to convert param?

For completeness, I've included an example for how to do this with vanilla Feign.

public class ZipCodeExpander implements Expander {
   public String expand(Object value) {
      // validate the object
      // throw an exception if the request is not valid.
   }
}

public interface ZipCodeClient {
    @RequestLine("GET /zipcodes/{zipCode}")
    Optional<ZipCodeView> findByZipCode(@Param(expander = ZipCodeExpander.class) ("zipCode") String zipCode);
}
Kevin Davis
  • 1,193
  • 8
  • 14
  • This is interesting.Unfortunately I found this too much Feign-dependent; what I have in mind - as the OP had probably too given he's using `@FeignClient`, which is a Spring Cloud/OpenFeign annotation - is to be able to use the Java Bean Validation (JSR 380) annotations which are supported de facto in Spring MVC, particularly because the `@GetMapping` is a Spring Web annotation that can be reused in this context (Spring Cloud/OpenFeign) to define the HTTP call/method signature. – maxxyme Nov 12 '19 at 14:22
0

As pointed out in this comment, a solution using the Bean Validation API would be nice. And indeed, I found in a Spring Boot project that merely placing @org.springframework.validation.annotation.Validated on the interface is sufficient for enabling Bean Validation.

So for example:

@FeignClient
@Validated
public interface ZipCodeClient {
    @GetMapping("/zipcodes/{zipCode}")
    Optional<ZipCodeView> findByZipCode(@PathVariable("zipCode") @NotEmpty String zipCode);
}

triggering a ConstraintViolationException in the case of violations.

Any standard Bean Validation feature should work here.

UDPATE Note that there seems to be a potential issue with this solution that might require setting a Hibernate Validator configuration property like this: hibernate.validator.allow_parallel_method_parameter_constraint=true

Hein Blöd
  • 1,553
  • 1
  • 18
  • 25