简体   繁体   中英

Spring JPA - RESTful partial update and validation for entity

I've a simple RESTful API based on Spring MVC using a JPA connected MySQL database. Until now this API supports complete updates of an entity only. This means all fields must be provided inside of the request body.

@ResponseBody
@PutMapping(value = "{id}")
public ResponseEntity<?> update(@Valid @RequestBody Article newArticle, @PathVariable("id") long id) {

    return service.updateById(id, newArticle);
}

The real problem here is the validation, how could I validate only provided fields while still require all fields during creation?

@Entity
public class Article {

    @NotEmpty @Size(max = 100) String title;
    @NotEmpty @Size(max = 500) String content;

    // Getters and Setters
}

Example for a partial update request body {"content": "Just a test"} instead of {"title": "Title", "content": "Just a test"} . The actual partial update is done by checking if the given field is not null:

if(newArticle.getTitle() != null) article.setTitle(newArticle.getTitle());

But the validation of course wont work! I've to deactivate the validation for the update method to run the RESTful service. I've essentially two questions:

  • How can I validate only a "existing" subset of properties in the update method while still require all fields during creation?
  • Is there a more elegant way for update partially then checking for null?

The complexity of partial updates and Spring JPA is that you may send half of the fields populated, and even that you will need to pull the entire entity from the data base, then just "merge" both entity and the pojo, because otherwise you will risk your data by sending null values to the database.

But merging itself is kind of tricky, because you need to operate over each field and take the decision of either send the new value to the data base or just keep the current one. And as you add fields, the validation needs to be updated, and tests get more complex. In one single statement: it doesn't scale . The idea is to always write code which is open for extension and closed for modifications. If you add more fields, then the validation block ideally doesn't need to change.

The way you deal with this in a REST model, is by operating over the entire entity each time you need. Let's say you have users, then you first pull a user:

GET /user/100

Then you have in your web page the entire fields of user id=100. Then you change its last name. You propagate the change calling the same resource URL with PUT verb:

PUT /user/100

And you send all the fields, or rather the "same entity" back with a new lastname. And you forget about validation, the validation will just work as a black box. If you add more fields, you add more @NotNull or whatever validation you need. Of course there may be situations where you need to actually write blocks of code for validation. Even in this case the validation doesn't get affected, as you will have a main for-loop for your validation, and each field will have its own validator. If you add fields, you add validators, but the main validation block remains untouchable.

Those are the most basic options for entity validation:

  1. You can annotate column with @NotNull , just as you did with other constraints.
  2. You can annotate the field with @Column(nullable = false) .

@Valid on the other hand validates object before entering the method.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM