Home > Enterprise >  Spring partial bean validation in PATCH request
Spring partial bean validation in PATCH request

Time:12-04

I'm making a Spring Boot application. I have an entity there:

@Entity
public class Employee {
    @NotNull
    private Category category;

    // Education related fields
    @NotNull
    private Education education;
    @NotBlank
    private String eduName;
    @NotNull
    private LocalDate eduGraduationDate;

    // other fields, getters, setters ...
}

As you can see, I have validation annotations there. But in my application I need to update the fields partially, e.g. client wants to update Education fields separately from Category field.

And the problem is that I cannot use PUT request to do that, because it will update whole object. If the Category field is actually null, and I want to update just the Education fields, I will get ConstraintViolationException, because the Category field is null. But it was null and I want it to be null further.

I can use PATCH request to do this:

@PatchMapping(path = "/{id}", consumes = "application/merge-patch json")
public ResponseEntity<Employee> patchEmployee(@PathVariable Long id, @RequestBody JsonMergePatch jsonMergePatch) throws JsonPatchException, JsonProcessingException {
    Employee employee = employeeDataService.findById(id).orElseThrow(() -> new ResourceNotFoundException("Employee not exist: id = "   id));
        
    Employee employeePatched = applyPatchToEmployee(jsonMergePatch, employee);

    return ResponseEntity.ok(employeeDataService.save(employeePatched));
}
    
private Employee applyPatchToEmployee(JsonMergePatch jsonMergePatch, Employee targetEmployee) throws JsonPatchException, JsonProcessingException {
    JsonNode patched = jsonMergePatch.apply(objectMapper.convertValue(targetEmployee, JsonNode.class));
    return objectMapper.treeToValue(patched, Employee.class);
}

But the question is: How can I validate my fields partially?

For example, if I send a PATCH request with body:

{
    "education":"HIGHER",
    "eduName":"MIT",
    "eduGraduationDate":"2020-05-05"
}

How can I validate only this 3 fields? Not the whole Employee object? In this example, as I mentioned above, I want the Category field to be null and I don't want to validate it, if it is not included in the patch.

Maybe there are some better approaches to partially update entities, if so - which?

CodePudding user response:

You can create a new DTO object with only fields you want to include for your PATCH call like,

EmployeePatchDto

public class EmployeePatchDto {

    // Education related fields
    @NotNull
    private Education education;
    @NotBlank
    private String eduName;
    @NotNull
    private LocalDate eduGraduationDate;

    // other fields, getters, setters ...
}

but now you'll still have to be sure that these validations are considered when you call the API. Also, you can opt to validate your DTO class at controller method level by using @Valid like this,

public ResponseEntity<Employee> patchEmployee(@PathVariable Long id, @Valid @RequestBody EmployeePatchDto employeeDto) throws JsonPatchException, JsonProcessingException {

I'l leave this resource for you. Read this.

  • Related