Skip to content

Latest commit

History

42 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

rest-patch

This library aims to aid in supporting patching for requests in Java-based RESTFUL webservices. It is not tied into Spring in anyway, but all examples here are shown using Spring Boot. It aims to support the logical way of handling REST patching in services like Stripe and Previsto and hence support JSON and FORM based requests.

What does it do?

Merging

First of all it allows you to patch a POJO upon another POJO of same type based on a list of dirty fields. You simply gather a list of dirty fields which you want to be patched from one POJO to another. You use the EntityMerger for this purpose as shown below.

Merge Example

publicvoidmain() {
EntityMergermerger = newEntityMerger();
Petpatch = newPet();
patch.setName("Bella");
patch.setKind(Kind.Cat);
Petoriginal = newPet();
original.setName("Barkley");
original.setKind(Kind.Dog);
List<String> dirtyFields = Collections.singletonList("name");
merger.mergeEntities(original, patch, dirtyFields);
System.out.println(original.getName()); // Outputs "Bella" (Was patched)System.out.println(original.getKind()); // Outputs "Dog" (Was NOT patched) 
}

Resolve dirty fields

Second, it allows you to gather the dirty fields from JSON(via Jackson) and FORM(via Java Map) requests. Checkout the following examples:

JSON Example (Spring Boot)

@RestControllerpublicclassPetController {
privateTreeNodePropertyReferenceConverterfieldConverter = newTreeNodePropertyReferenceConverter();
privateEntityMerger<Pet> merger = newEntityMerger();
@PutMapping("/pets/{id}")
publicPetupdate(@RequestBodyPetpatch, @PathVariableStringid) {
Petoriginal = ...; // Get original from backendList<String> fields = fieldConverter.translate(TreeNodeHolder.get());
Petmerge = this.merger.mergeEntities(original, patch, fields);
... // Save merge to backend
} }

The above example allows us to send just the fields we want to update, fx. {"name": "Bessie"}, without overwriting other fields.

Note on thread safety:TreeNodeHolder is a single slot per thread and is cleared at the start of every capture, so a failed request never leaves stale data behind. Always consume the captured node immediately and release it in a finally block:

try {
Petoriginal = ...;
List<String> fields = fieldConverter.translate(TreeNodeHolder.get());
...
} finally {
TreeNodeHolder.clear();
}

Getting dirty fields without thread-local state (recommended)

If you control the ObjectMapper, use a JacksonTreeNodeMapper and the Patched API instead. The raw tree node is returned together with the deserialized value, so no thread-local state is involved at all:

@RestControllerpublicclassPetController {
privateJacksonTreeNodeMappermapper = newJacksonTreeNodeMapper();
privateEntityMerger<Pet> merger = newEntityMerger();
@PutMapping("/pets/{id}")
publicPetupdate(@RequestBodyStringpayload, @PathVariableStringid) throwsIOException {
Petoriginal = ...; // Get original from backendPatched<Pet> patched = mapper.readPatchedValue(payload, Pet.class);
List<String> fields = patched.dirtyFields();
Petmerge = this.merger.mergeEntities(original, patched.value(), fields);
... // Save merge to backend
}
}

It gives you the same flexibility with FORM input which is handy when it comes to supporting access to the API via cUrl.

FORM Example (Spring Boot)

@RestControllerpublicclassPetController {
privateFormPropertyReferenceConverterfieldConverter = newFormPropertyReferenceConverter();
privateEntityMerger<Pet> merger = newEntityMerger();
@PutMapping("/pets/{id}", consumes = "application/x-www-form-urlencoded")
publicPetupdate(@ModelAttributePetpatch, @PathVariableStringid, HttpServletRequestrequest) {
Petoriginal = ...; // Get original from backendList<String> fields = fieldConverter.translate(request.getParameterMap());
Petmerge = this.merger.mergeEntities(original, patch, fields);
... // Save merge to backend
} }

The above example allows us to send just the fields we want to update via cUrl, fx. curl -X PUT -d name=Bessie http://server/pets/{id}, without overwriting other fields.

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages