Example demonstrating how to validate complex header scenarios with Spring filters.
There are 3 main components:
HeaderRequirementFilterHeaderRequirementHeaderRequirementSpec
If you're not familiar with filters, you should probably check out this article before reading any further.
The HeaderRequirementFilter is dependent on configured header requirements and makes use of these to determine if the
headers on the incoming request are valid or not. If the headers are valid the chain executes normally, otherwise
a 400 Bad Request response is sent directly from the filter implementation.
HeaderRequirements simply accept a HttpServletRequest and produce a Set<ConstraintViolation<T>>. The T in this
case is the spec that will be used to validate the header values against using a javax.Validator. This solution also
comes with a BaseHeaderRequirement that comes with the common validation functionality out of the box. Making your
own HeaderRequirement might look like the below:
import com.sexton.example.filter.BaseHeaderRequirement;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Component
public class ExampleHeaderRequirement extends BaseHeaderRequirement<ExampleHeaderRequirementSpec> {
@Override
protected ExampleHeaderRequirementSpec buildValidationSpec(HttpServletRequest request) {
return ExampleHeaderRequirementSpec.builder()
.name(request.getHeader("X-Example-Header"))
.build();
}
}Make sure the HeaderRequirement is decorated with @Component so that it is automatically configured with Spring and
injected into the filter.
The spec is the POJO object that the headers will be mapped too and validated by hibernate. Below is a simple example:
import lombok.Builder;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
// Spec includes example headers that an API might require
@Data
@Builder
public class ExampleHeaderRequirementSpec {
@NotEmpty
private final String example;
}In a single project this solution is probably a good example of over engineering unless you really just want to make use of hibernate when validating incoming headers.
This solutions really shines as a reusable pattern due to header requirements being decoupled from the filter, and the ability to make use of the entire hibernate validation ecosystem.