Brug af JSON Patch i REST API'er for foråret

1. Introduktion

Af de forskellige tilgængelige HTTP-metoder spiller HTTP PATCH-metoden en unik rolle. Det giver os mulighed for at anvende delvise opdateringer til HTTP-ressourcer.

I denne vejledning ser vi på, hvordan du bruger HTTP PATCH-metoden sammen med JSON Patch-dokumentformatet til at anvende delvise opdateringer til vores RESTful-ressourcer.

2. Brugssagen

Lad os starte med at overveje et eksempel på HTTP Kunde ressource repræsenteret af JSON-dokumentet:

{"id": "1", "telephone": "001-555-1234", "favorites": ["Mælk", "Æg"], "communicationPreferences": {"post": true, "email": rigtigt} }

Lad os antage, at denne kundes telefonnummerer ændret, og at kunden tilføjede et nyt element til deres liste over yndlingsprodukter. Dette betyder, at vi kun skal opdatere telefon og favoritter felter i Kunde.

Hvordan ville vi gøre det?

Den populære HTTP PUT-metode kommer først til at tænke på. Men fordi PUT erstatter en ressource helt, er det ikke en passende metode til at anvende delvise opdateringer elegant. Desuden skal klienterne udføre en GET, før opdateringerne anvendes og gemmes.

Dette er hvor HTTP PATCH-metoden er praktisk.

Lad os forstå HTTP PATCH-metoden og JSON Patch-formaterne.

3. HTTP PATCH-metoden og JSON Patch Format

HTTP PATCH-metoden giver en god måde at anvende delvise opdateringer på ressourcer på. Som et resultat skal klienter kun sende forskellene i deres anmodninger.

Lad os se på et simpelt eksempel på en HTTP PATCH-anmodning:

PATCH / kunder / 1234 HTTP / 1.1 Host: www.example.com Content-Type: application / example If-Match: "e0023aa4e" Content-Length: 100 [beskrivelse af ændringer]

HTTP PATCH-anmodningsorganet beskriver, hvordan målressourcen skal ændres for at producere en ny version. Desuden er det format, der bruges til at repræsentere [beskrivelse af ændringer] varierer afhængigt af ressourcetypen. For JSON-ressourcetyper er formatet, der bruges til at beskrive ændringerne, JSON Patch.

Kort sagt bruger JSON Patch-formatet en "række operationer" til at beskrive, hvordan målressourcen skal ændres. Et JSON Patch-dokument er en matrix med JSON-objekter. Hvert objekt i arrayet repræsenterer nøjagtigt en JSON Patch-operation.

Lad os nu se på JSON Patch-operationerne sammen med nogle eksempler.

4. JSON Patch-operationer

En JSON Patch-operation er repræsenteret af en enkelt op objekt.

For eksempel definerer vi her en JSON-patchoperation for at opdatere kundens telefonnummer:

{"op": "udskift", "sti": "/ telefon", "værdi": "001-555-5678"}

Hver operation skal have en sti medlem. Nogle funktionsobjekter skal også indeholde en fra medlem også. Værdien af sti og fra medlemmer er en JSON-markør. Det refererer til en placering i måldokumentet. Denne placering kan pege på en bestemt nøgle eller et matrixelement i målobjektet.

Lad os nu kort se på de tilgængelige JSON Patch-operationer.

4.1. Det tilføje Operation

Vi bruger tilføje operation for at tilføje et nyt medlem til et objekt. Vi kan også bruge den til at opdatere et eksisterende medlem og til at indsætte en ny værdi i arrayet ved det angivne indeks.

Lad os for eksempel tilføje "Brød" til kundens favoritter liste ved indeks 0:

{"op": "add", "path": "/ favourites / 0", "value": "Brød"}

De ændrede kundeoplysninger efter tilføje operation ville være:

{"id": "1", "telephone": "001-555-1234", "favourites": ["Bread", "Milk", "Eggs"], "communicationPreferences": {"post": true, "e-mail": sand}}

4.2. Det fjerne Operation

Det fjerne operation fjerner en værdi på målplaceringen. Desuden kan det fjerne et element fra et array ved det angivne indeks.

Lad os for eksempel fjerne kommunikationPræferencer til vores kunde:

{"op": "remove", "path": "/ communicationPreferences"}

De ændrede kundeoplysninger efter fjerne operation ville være:

{"id": "1", "telephone": "001-555-1234", "favorites": ["Brød", "Mælk", "Æg"], "communicationPreferences": null}

4.3. Det erstatte Operation

Det erstatte operation opdaterer værdien på målplaceringen med en ny værdi.

Lad os som et eksempel opdatere telefonnummeret til vores kunde:

{"op": "udskift", "sti": "/ telefon", "værdi": "001-555-5678"}

De ændrede kundeoplysninger efter erstatte operation ville være:

{"id": "1", "telephone": "001-555-5678", "favorites": ["Bread", "Milk", "Eggs"], "communicationPreferences": null}

4.4. Det bevæge sig Operation

Det bevæge sig operation fjerner værdien på den angivne placering og føjer den til målplaceringen.

Lad os for eksempel flytte “Brød” fra toppen af ​​kundens favoritter liste til bunden af ​​listen:

{"op": "move", "from": "/ favourites / 0", "path": "/ favourites / -"}

De ændrede kundeoplysninger efter bevæge sig operation ville være:

{"id": "1", "telephone": "001-555-5678", "favourites": ["Mælk", "Æg", "Brød"], "communicationPreferences": null} 

Det / favoritter / 0 og / favoritter / - i ovenstående eksempel er der JSON-markører til start- og slutindekserne for favoritter array.

4.5. Det kopi Operation

Det kopi handling kopierer værdien på den angivne placering til målplaceringen.

Lad os f.eks. Duplikere "Mælk" i favoritter liste:

{"op": "kopi", "fra": "/ favoritter / 0", "sti": "/ favoritter / -"}

De ændrede kundeoplysninger efter kopi operation ville være:

{"id": "1", "telephone": "001-555-5678", "favourites": ["Mælk", "Æg", "Brød", "Mælk"], "communicationPreferences": null}

4.6. Det prøve Operation

Det prøve operation tester, at værdien på "stien" er lig med "værdien". Da PATCH-operationen er atomær, skal PATCH'en kasseres, hvis nogen af ​​dens operationer mislykkes. Det prøve operation kan bruges til at validere, at forudsætningerne og efterbetingelserne er opfyldt.

Lad os for eksempel teste, at opdateringen til kundens telefon felt har været vellykket:

{"op": "test", "sti": "/ telefon", "værdi": "001-555-5678"} 

Lad os nu se, hvordan vi kan anvende ovenstående begreber i vores eksempel.

5. HTTP PATCH-anmodning ved hjælp af JSON Patch Format

Vi besøger vores igen Kunde brugssag.

Her er HTTP PATCH-anmodningen om at udføre en delvis opdatering til kundens telefon og favoritter liste ved hjælp af JSON Patch-format:

krølle -i -X ​​PATCH // localhost: 8080 / kunder / 1 -H "Indholdstype: applikation / json-patch + json" -d '[{"op": "udskift", "sti": "/ telefon "," værdi ":" + 1-555-56 "}, {" op ":" tilføj "," sti ":" / favoritter / 0 "," værdi ":" Brød "}] ' 

Vigtigst er det, at Indholdstype for JSON Patch-anmodninger er applikation / json-patch + json. Anmodningslegemet er også en matrix af JSON Patch-funktionsobjekter:

[{"op": "erstatte", "sti": "/ telefon", "værdi": "+ 1-555-56"}, {"op": "tilføj", "sti": "/ favoritter / 0 "," value ":" Brød "}]

Hvordan ville vi behandle en sådan anmodning på serversiden?

En måde er at skrive en brugerdefineret ramme, der evaluerer operationerne sekventielt og anvender dem på målressourcen som en atomenhed. Denne tilgang lyder helt klart kompliceret. Det kan også føre til en ikke-standardiseret måde at forbruge patch-dokumenter på.

Heldigvis behøver vi ikke håndarbejde behandlingen af ​​JSON Patch-anmodninger.

Java API til JSON Processing 1.0 eller JSON-P 1.0, oprindeligt defineret i JSR 353, introducerede understøttelse af JSON Patch i JSR 374. JSON-P API giver JsonPatch skriv for at repræsentere JSON Patch-implementeringen.

JSON-P er dog kun en API. For at arbejde med JSON-P API er vi nødt til at bruge et bibliotek, der implementerer det. Vi bruger et sådant bibliotek kaldet json-patch til eksemplerne i denne artikel.

Lad os nu se på, hvordan vi kan opbygge en REST-tjeneste, der bruger HTTP PATCH-anmodninger ved hjælp af JSON Patch-formatet beskrevet ovenfor.

6. Implementering af JSON Patch i en Spring Boot-applikation

6.1. Afhængigheder

Den nyeste version af json-patch kan findes fra Maven Central repository.

Lad os begynde med at tilføje afhængighederne til pom.xml:

 com.github.java-json-tools json-patch 1.12 

Lad os nu definere en skemaklasse, der skal repræsentere Kunde JSON-dokument:

offentlig klasse kunde {privat streng-id; privat String telefon; private liste favoritter; privat kortkommunikation Præferencer; // standard getters og setter}

Dernæst ser vi på vores controller-metode.

6.2. REST-controllermetoden

Derefter kan vi implementere HTTP PATCH til vores kundeanvendelsessag:

@PatchMapping (sti = "/ {id}", forbruger = "applikation / json-patch + json") offentlig ResponseEntity updateCustomer (@PathVariable String id, @RequestBody JsonPatch patch) {prøv {Kundekunde = customerService.findCustomer (id) .orElseThrow (CustomerNotFoundException :: ny); Kundekundepatch = ApplyPatchToCustomer (programrettelse, kunde); customerService.updateCustomer (customerPatched); returnere ResponseEntity.ok (customerPatched); } fangst (JsonPatchException | JsonProcessingException e) {return ResponseEntity.status (HttpStatus.INTERNAL_SERVER_ERROR) .build (); } fange (CustomerNotFoundException e) {return ResponseEntity.status (HttpStatus.NOT_FOUND) .build (); }} 

Lad os nu forstå, hvad der foregår i denne metode:

  • Til at begynde med bruger vi @PatchMapping kommentar for at markere metoden som en PATCH-håndteringsmetode
  • Når en patchanmodning med applikation / json-patch + json "Content-Type" ankommer, Spring Boot bruger standard MappingJackson2HttpMessageConverter at konvertere anmodningen nyttelast til en JsonPatch eksempel. Som et resultat modtager vores controller-metode anmodningsorganet som en JsonPatch eksempel

Inden for metoden:

  1. Først kalder vi customerService.findCustomer (id) metode til at finde kundeposten
  2. Efterfølgende, hvis kundeoptegnelsen findes, påberåber vi os applyPatchToCustomer (patch, kunde) metode. Dette gælder JsonPatch til kunden (mere om dette senere)
  3. Vi påberåber os derefter customerService.updateCustomer (customerPatched) for at gemme kundeoptegnelsen
  4. Endelig returnerer vi en 200 OK svar til klienten med den patchede Kunde detaljer i svaret

Vigtigst er det, at den virkelige magi sker i ApplyPatchToCustomer (patch, kunde) metode:

privat kunde ApplyPatchToCustomer (JsonPatch patch, Customer targetCustomer) kaster JsonPatchException, JsonProcessingException {JsonNode patched = patch.apply (objectMapper.convertValue (targetCustomer, JsonNode.class)); returner objectMapper.treeToValue (patched, Customer.class); } 
  1. Til at begynde med har vi vores JsonPatch forekomst, der indeholder listen over operationer, der skal anvendes på målet Kunde
  2. Vi konverterer derefter målet Kunde ind i en instans af com.fasterxml.jackson.databind.JsonNode og videregive det til JsonPatch.apply metode til at anvende plasteret. Bag kulisserne er den JsonPatch.apply beskæftiger sig med at anvende operationerne på målet. Resultatet af plasteret er også et com.fasterxml.jackson.databind.JsonNode eksempel
  3. Vi kalder derefter objectMapper.treeToValue metode, som binder dataene i den patchede com.fasterxml.jackson.databind.JsonNode til Kunde type. Dette er vores lappede Kunde eksempel
  4. Endelig returnerer vi den lappede Kunde eksempel

Lad os nu køre nogle tests mod vores API.

6.3. Testning

Til at begynde med skal vi oprette en kunde ved hjælp af en POST-anmodning til vores API:

krølle -i -X ​​POST // localhost: 8080 / kunder -H "Content-Type: application / json" -d '{"telephone": "+ 1-555-12", "favourites": ["Milk", "Æg"], "communicationPreferences": {"post": true, "email": true}} ' 

Vi modtager en 201 Oprettet respons:

HTTP / 1.1 201 Placering: // localhost: 8080 / kunder / 1 

Det Beliggenhed svarhoved er indstillet til placeringen af ​​den nye ressource. Det indikerer, at id af det nye Kunde er 1.

Lad os derefter anmode om en delvis opdatering til denne kunde ved hjælp af en PATCH-anmodning:

krølle -i -X ​​PATCH // localhost: 8080 / kunder / 1 -H "Indholdstype: applikation / json-patch + json" -d '[{"op": "udskift", "sti": "/ telefon "," værdi ":" + 1-555-56 "}, {" op ":" tilføj "," sti ":" / favoritter / 0 "," værdi ":" Brød "}] '

Vi modtager en 200Okay svar med de opdaterede kundeoplysninger:

HTTP / 1.1 200 Indholdstype: applikation / json Overførsel-kodning: klumpet dato: Fre, 14. feb 2020 21:23:14 GMT {"id": "1", "telefon": "+ 1-555-56" , "favorites": ["Bread", "Milk", "Eggs]]," communicationPreferences ": {" post ": true," email ": true}}

7. Konklusion

I denne artikel så vi på, hvordan JSON Patch implementeres i Spring REST API'er.

Til at begynde med så vi på HTTP PATCH-metoden og dens evne til at udføre delvise opdateringer.

Vi kiggede derefter på, hvad der er JSON Patch og forstod de forskellige JSON Patch-operationer.

Endelig diskuterede vi, hvordan man håndterer en HTTP PATCH-anmodning i en Spring Boot-applikation ved hjælp af json-patch-biblioteket.

Som altid er kildekoden til eksemplerne i denne artikel tilgængelig på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found