Korištenje JSON Patch-a u Spring REST API-ima

1. Uvod

Od različitih dostupnih HTTP metoda, metoda HTTP PATCH igra jedinstvenu ulogu. Omogućuje nam primjenu djelomičnih ažuriranja na HTTP resurse.

U ovom ćemo uputstvu pogledati kako koristiti metodu HTTP PATCH zajedno s formatom dokumenta JSON Patch za primjenu djelomičnih ažuriranja na naše RESTful resurse.

2. Slučaj upotrebe

Krenimo od razmatranja primjera HTTP-a Kupac resurs predstavljen JSON dokumentom:

{"id": "1", "telephone": "001-555-1234", "favorite": ["Mlijeko", "Jaja"], "communicationPreferences": {"post": true, "email": istina}}

Pretpostavimo da je telefonski broj ovog kupcase promijenio i da je kupac dodao novu stavku na svoj popis omiljenih proizvoda. To znači da trebamo ažurirati samo telefon i omiljeni polja Kupac.

Kako bismo to učinili?

Najprije mi padne na pamet popularna metoda HTTP PUT. Međutim, budući da PUT u potpunosti zamjenjuje resurs, nije prikladna metoda za elegantnu primjenu djelomičnih ažuriranja. Štoviše, klijenti moraju izvršiti GET prije nego što se ažuriranja primijene i spreme.

Tu dobro dolazi metoda HTTP PATCH.

Razumijemo metodu HTTP PATCH i formate JSON Patch.

3. HTTP PATCH metoda i JSON oblik zakrpe

HTTP PATCH metoda nudi lijep način primjene djelomičnih ažuriranja na resurse. Kao rezultat toga, klijenti trebaju slati samo razlike u svojim zahtjevima.

Pogledajmo jednostavan primjer zahtjeva za HTTP PATCH:

PATCH / customers / 1234 HTTP / 1.1 Host: www.example.com Tip sadržaja: aplikacija / primjer If-Match: "e0023aa4e" Duljina sadržaja: 100 [opis promjena]

Tijelo zahtjeva HTTP PATCH opisuje kako ciljni resurs treba izmijeniti kako bi se proizvela nova verzija. Nadalje, format koji se koristi za predstavljanje [opis promjena] varira ovisno o vrsti resursa. Za tipove resursa JSON format koji se koristi za opisivanje promjena je JSON zakrpa.

Jednostavno rečeno, format JSON Patch koristi "niz operacija" da opiše kako ciljni resurs treba modificirati. JSON Patch dokument je niz JSON objekata. Svaki objekt u polju predstavlja točno jednu operaciju JSON Patch.

Pogledajmo sada JSON Patch operacije zajedno s nekoliko primjera.

4. JSON zakrpe

JSON Patch operacija predstavljena je jednim op objekt.

Na primjer, ovdje definiramo JSON operaciju zakrpe za ažuriranje korisničkog telefonskog broja:

{"op": "replace", "path": "/ telephone", "value": "001-555-5678"}

Svaka operacija mora imati po jednog staza član. Također, neki operativni objekti moraju sadržavati a iz član također. Vrijednost staza i iz members je JSON pokazivač. Odnosi se na mjesto unutar ciljnog dokumenta. Ovo mjesto može ukazivati ​​na određeni ključ ili element niza u ciljnom objektu.

Pogledajmo sada ukratko dostupne JSON Patch operacije.

4.1. The dodati Operacija

Koristimo dodati operacija dodavanja novog člana u objekt. Također, možemo ga koristiti za ažuriranje postojećeg člana i za umetanje nove vrijednosti u niz s navedenim indeksom.

Na primjer, dodajmo kupcu "Kruh" omiljeni popis u indeksu 0:

{"op": "dodaj", "put": "/ omiljeno / 0", "vrijednost": "kruh"}

Izmijenjeni detalji kupca nakon dodati operacija bi bila:

{"id": "1", "telephone": "001-555-1234", "favorite": ["Kruh", "Mlijeko", "Jaja"], "communicationPreferences": {"post": true, "email": true}}

4.2. The ukloniti Operacija

The ukloniti operacija uklanja vrijednost na ciljnom mjestu. Osim toga, može ukloniti element iz niza na navedenom indeksu.

Na primjer, uklonimo komunikacijaPrednosti za našeg kupca:

{"op": "ukloni", "put": "/ communicationPreferences"}

Izmijenjeni detalji kupca nakon ukloniti operacija bi bila:

{"id": "1", "telephone": "001-555-1234", "favorite": ["Kruh", "Mlijeko", "Jaja"], "communicationPreferences": null}

4.3. The zamijeniti Operacija

The zamijeniti operacija ažurira vrijednost na ciljnom mjestu novom vrijednošću.

Kao primjer, ažurirajmo telefonski broj za našeg kupca:

{"op": "replace", "path": "/ telephone", "value": "001-555-5678"}

Izmijenjeni detalji kupca nakon zamijeniti operacija bi bila:

{"id": "1", "telephone": "001-555-5678", "favorite": ["Kruh", "Mlijeko", "Jaja"], "communicationPreferences": null}

4.4. The potez Operacija

The potez operacija uklanja vrijednost na navedenom mjestu i dodaje je na ciljno mjesto.

Na primjer, pomaknimo kruh s vrha kupca omiljeni popis na dnu popisa:

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

Izmijenjeni detalji kupca nakon potez operacija bi bila:

{"id": "1", "telephone": "001-555-5678", "favorite": ["Mlijeko", "Jaja", "Kruh"], "communicationPreferences": null} 

The / favorite / 0 i / omiljeni / - u gornjem primjeru su JSON pokazivači na početni i krajnji indeks omiljeni niz.

4.5. The kopirati Operacija

The kopirati operacija kopira vrijednost na navedenom mjestu na ciljno mjesto.

Na primjer, duplicirajmo "Mlijeko" u omiljeni popis:

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

Izmijenjeni detalji kupca nakon kopirati operacija bi bila:

{"id": "1", "telephone": "001-555-5678", "favorite": ["Mlijeko", "Jaja", "Kruh", "Mlijeko"], "communicationPreferences": null}

4.6. The test Operacija

The test operativni testovi da je vrijednost na "putu" jednaka "vrijednosti". Budući da je operacija PATCH atomska, PATCH treba odbaciti ako bilo koja od njenih operacija ne uspije. The test operacija se može koristiti za provjeru jesu li ispunjeni preduvjeti i post-uvjeti.

Na primjer, testirajmo ažuriranje za kupca telefon polje je uspješno:

{"op": "test", "path": "/ telefon", "value": "001-555-5678"} 

Pogledajmo sada kako možemo primijeniti gornje koncepte na svoj primjer.

5. Zahtjev za HTTP PATCH pomoću JSON formata zakrpe

Ponovno ćemo posjetiti naše Kupac slučaj upotrebe.

Ovdje je HTTP PATCH zahtjev za izvođenjem djelomičnog ažuriranja korisnikovog telefon i omiljeni popis koristeći JSON Patch format:

curl -i -X ​​PATCH // localhost: 8080 / customers / 1 -H "Content-Type: application / json-patch + json" -d '[{"op": "replace", "path": "/ telephone "," value ":" + 1-555-56 "}, {" op ":" add "," path ":" / favorites / 0 "," value ":" Kruh "}] ' 

Najvažnije je Vrsta sadržaja za JSON Patch zahtjeve je application / json-patch + json. Također, tijelo zahtjeva je niz operativnih objekata JSON Patch:

[{"op": "replace", "path": "/ telephone", "value": "+ 1-555-56"}, {"op": "dodaj", "put": "/ omiljeni / 0 "," value ":" Kruh "}]

Kako bismo obradili takav zahtjev na strani poslužitelja?

Jedan od načina je pisanje prilagođenog okvira koji redom procjenjuje operacije i primjenjuje ih na ciljni resurs kao atomsku jedinicu. Jasno je da ovaj pristup zvuči složeno. Također, to može dovesti do nestandardiziranog načina konzumiranja zakrpnih dokumenata.

Srećom, ne moramo ručno izraditi obradu zahtjeva za JSON zakrpe.

Java API za JSON Processing 1.0 ili JSON-P 1.0, definiran izvorno u JSR 353, uveo je podršku za JSON Patch u JSR 374. JSON-P API pruža JsonPatch tip koji predstavlja implementaciju JSON zakrpe.

Međutim, JSON-P je samo API. Da bismo radili s JSON-P API-jem, trebamo koristiti knjižnicu koja ga implementira. Za primjere u ovom članku koristit ćemo jednu takvu knjižnicu koja se naziva json-patch.

Pogledajmo sada kako možemo izgraditi REST uslugu koja troši HTTP PATCH zahtjeve koristeći gore opisani format JSON Patch.

6. Implementacija JSON zakrpe u Spring Boot Application

6.1. Ovisnosti

Najnoviju verziju json-patcha možete pronaći iz spremišta Maven Central.

Za početak dodajmo ovisnosti na pom.xml:

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

Sada, definirajmo klasu sheme koja će predstavljati Kupac JSON dokument:

kupac javne klase {id privatnog niza; privatni gudački telefon; privatni popis favorita; privatna karta komunikacijaPreference; // standardni geteri i postavljači}

Dalje ćemo pogledati našu metodu kontrolera.

6.2. Metoda REST kontrolera

Tada možemo implementirati HTTP PATCH za slučaj upotrebe naših kupaca:

@PatchMapping (path = "/ {id}", konzumira = "application / json-patch + json") javni ResponseEntity updateCustomer (@PathVariable String id, @RequestBody JsonPatch patch) {try {Customer customer = customerService.findCustomer (id) .orElseThrow (CustomerNotFoundException :: novo); Kupac customerPatched = applyPatchToCustomer (zakrpa, kupac); customerService.updateCustomer (customerPatched); vratiti ResponseEntity.ok (customerPatched); } catch (JsonPatchException | JsonProcessingException e) {return ResponseEntity.status (HttpStatus.INTERNAL_SERVER_ERROR) .build (); } catch (CustomerNotFoundException e) {return ResponseEntity.status (HttpStatus.NOT_FOUND) .build (); }} 

Ajmo sada razumjeti što se događa u ovoj metodi:

  • Za početak koristimo @PatchMapping napomena za označavanje metode kao metode obrade PATCH-a
  • Kada se zakrpa zatraži s application / json-patch + json Stiže "Content-Type", Spring Boot koristi zadanu postavku MappingJackson2HttpMessageConverter pretvoriti korisni teret zahtjeva u JsonPatch primjer. Kao rezultat, naša metoda kontrolera primit će tijelo zahtjeva kao JsonPatch primjer

Unutar metode:

  1. Prvo zovemo customerService.findCustomer (id) metoda za pronalaženje evidencije kupaca
  2. Nakon toga, ako se pronađe evidencija kupaca, pozivamo se na applyPatchToCustomer (zakrpa, kupac) metoda. Ovo se odnosi na JsonPatch kupcu (više o tome kasnije)
  3. Zatim pozivamo customerService.updateCustomer (customerPatched) za spremanje evidencije kupaca
  4. Konačno, vraćamo a 200 OK odgovor klijentu s zakrpanim Kupac detalji u odgovoru

Najvažnije je da se prava čarolija događa u applyPatchToCustomer (zakrpa, kupac) metoda:

privatni kupac applyPatchToCustomer (JsonPatch zakrpa, kupac targetCustomer) baca JsonPatchException, JsonProcessingException {JsonNode zakrpan = patch.apply (objectMapper.convertValue (targetCustomer, JsonNode.class)); vratiti objectMapper.treeToValue (zakrpano, Customer.class); } 
  1. Za početak imamo svoje JsonPatch instanca koja sadrži popis operacija koje će se primijeniti na cilj Kupac
  2. Zatim pretvaramo cilj Kupac u primjerak com.fasterxml.jackson.databind.JsonNode i proslijedite ga na JsonPatch.apply metoda za primjenu flastera. Iza kulisa, JsonPatch.apply bavi se primjenom operacija na cilj. Rezultat zakrpe je također a com.fasterxml.jackson.databind.JsonNode primjer
  3. Zatim zovemo objectMapper.treeToValue metoda koja povezuje podatke u zakrpljenom com.fasterxml.jackson.databind.JsonNode prema Kupac tip. Ovo je naše zakrpano Kupac primjer
  4. Napokon vraćamo zakrpljeno Kupac primjer

Pokrenimo sada neke testove protiv našeg API-ja.

6.3. Testiranje

Za početak stvorimo kupca pomoću POST zahtjeva za naš API:

curl -i -X ​​POST // localhost: 8080 / kupci -H "Content-Type: application / json" -d '{"telephone": "+ 1-555-12", "favorite": ["Milk", "Jaja"], "communicationPreferences": {"post": true, "email": true}} ' 

Primamo a 201 Stvoreno odgovor:

HTTP / 1.1 201 Mjesto: // localhost: 8080 / customers / 1 

The Mjesto odgovor zaglavlje postavljeno je na mjesto novog resursa. To ukazuje na to da iskaznica novog Kupac je 1.

Dalje, zatražimo djelomično ažuriranje za ovog kupca pomoću zahtjeva PATCH:

curl -i -X ​​PATCH // localhost: 8080 / customers / 1 -H "Content-Type: application / json-patch + json" -d '[{"op": "replace", "path": "/ telephone "," value ":" + 1-555-56 "}, {" op ":" add "," path ":" / favorites / 0 "," value ":" Kruh "}] '

Primamo a 200u redu odgovor s zakrpljenim pojedinostima kupca:

HTTP / 1.1 200 Sadržaj-vrsta: application / json Prijenos-kodiranje: podijeljeno Datum: Pet, 14. veljače 2020. 21:23:14 GMT {"id": "1", "telephone": "+ 1-555-56" , "favorite": ["Kruh", "Mlijeko", "Jaja"], "communicationPreferences": {"post": true, "email": true}}

7. Zaključak

U ovom smo članku pogledali kako implementirati JSON Patch u Spring REST API-je.

Za početak smo pogledali metodu HTTP PATCH i njegovu sposobnost izvođenja djelomičnih ažuriranja.

Zatim smo pogledali što je JSON Patch i razumjeli različite JSON Patch operacije.

Na kraju smo razgovarali o tome kako postupati s HTTP PATCH zahtjevom u aplikaciji Spring Boot pomoću biblioteke json-patch.

Kao i uvijek, izvorni kod za primjere korištene u ovom članku dostupan je na GitHubu.


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