Bruker JSON Patch i REST APIer for våren

1. Introduksjon

Av de forskjellige tilgjengelige HTTP-metodene spiller HTTP PATCH-metoden en unik rolle. Det lar oss bruke delvise oppdateringer til HTTP-ressurser.

I denne opplæringen vil vi se på hvordan du bruker HTTP PATCH-metoden sammen med JSON Patch-dokumentformatet for å bruke delvise oppdateringer til våre RESTful-ressurser.

2. Brukssaken

La oss starte med å vurdere et eksempel på HTTP Kunde ressurs representert av JSON-dokumentet:

{"id": "1", "telephone": "001-555-1234", "favourites": ["Melk", "Egg"], "communicationPreferences": {"post": true, "email": sant}}

La oss anta at denne kundens telefonnummerhar endret seg og at kunden la til et nytt element i listen over favorittprodukter. Dette betyr at vi bare trenger å oppdatere telefon og favoritter felt av Kunde.

Hvordan skulle vi gjøre det?

Den populære HTTP PUT-metoden kommer til å tenke først. Men fordi PUT erstatter en ressurs helt, er det ikke en passende metode for å bruke delvise oppdateringer elegant. Videre må klientene utføre en GET før oppdateringene blir brukt og lagret.

Dette er hvor HTTP PATCH-metoden kommer til nytte.

La oss forstå HTTP PATCH-metoden og JSON Patch-formatene.

3. HTTP PATCH-metoden og JSON Patch Format

HTTP PATCH-metoden gir en fin måte å bruke delvise oppdateringer på ressursene. Som et resultat må klienter bare sende forskjellene i deres forespørsler.

La oss se på et enkelt eksempel på en HTTP PATCH-forespørsel:

PATCH / kunder / 1234 HTTP / 1.1 Vert: www.example.com Innholdstype: applikasjon / eksempel If-Match: "e0023aa4e" Innholdslengde: 100 [beskrivelse av endringer]

HTTP PATCH-forespørselsorganet beskriver hvordan målressursen skal modifiseres for å produsere en ny versjon. Videre formatet som brukes til å representere [beskrivelse av endringer] varierer avhengig av ressurstype. For JSON-ressurstyper er formatet som brukes til å beskrive endringene JSON Patch.

Enkelt sagt, JSON Patch-format bruker en "serie operasjoner" for å beskrive hvordan målressursen skal modifiseres. Et JSON Patch-dokument er en rekke JSON-objekter. Hvert objekt i matrisen representerer nøyaktig en JSON Patch-operasjon.

La oss nå se på JSON Patch-operasjonene sammen med noen eksempler.

4. JSON Patch-operasjoner

En JSON Patch-operasjon er representert av en enkelt op gjenstand.

For eksempel definerer vi her en JSON-patchoperasjon for å oppdatere kundens telefonnummer:

{"op": "erstatt", "sti": "/ telefon", "verdi": "001-555-5678"}

Hver operasjon må ha en sti medlem. Noen operasjonsobjekter må også inneholde en fra medlem også. Verdien av sti og fra medlemmer er en JSON-peker. Det refererer til en plassering i måldokumentet. Denne plasseringen kan peke på en bestemt nøkkel eller et matriseelement i målobjektet.

La oss nå kort se på tilgjengelige JSON Patch-operasjoner.

4.1. De legge til Operasjon

Vi bruker legge til operasjon for å legge til et nytt medlem til et objekt. Vi kan også bruke den til å oppdatere et eksisterende medlem og til å sette inn en ny verdi i matrisen ved den spesifiserte indeksen.

La oss for eksempel legge til "brød" til kundens favoritter liste ved indeks 0:

{"op": "add", "path": "/ favorites / 0", "value": "Bread"}

De modifiserte kundeopplysningene etter legge til operasjonen vil være:

{"id": "1", "telephone": "001-555-1234", "favourites": ["Brød", "Melk", "Egg"], "communicationPreferences": {"post": true, "e-post": sann}}

4.2. De fjerne Operasjon

De fjerne operasjon fjerner en verdi på målplasseringen. Dessuten kan det fjerne et element fra en matrise ved den angitte indeksen.

La oss for eksempel fjerne kommunikasjonPreferanser for våre kunder:

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

De modifiserte kundeopplysningene etter fjerne operasjonen vil være:

{"id": "1", "telephone": "001-555-1234", "favourites": ["Brød", "Melk", "Egg"], "communicationPreferences": null}

4.3. De erstatte Operasjon

De erstatte operasjonen oppdaterer verdien på målplasseringen med en ny verdi.

La oss som et eksempel oppdatere telefonnummeret til kunden vår:

{"op": "erstatt", "sti": "/ telefon", "verdi": "001-555-5678"}

De modifiserte kundeopplysningene etter erstatte operasjonen vil være:

{"id": "1", "telephone": "001-555-5678", "favourites": ["Brød", "Melk", "Egg"], "communicationPreferences": null}

4.4. De bevege seg Operasjon

De bevege seg operasjonen fjerner verdien på den angitte plasseringen og legger den til målplasseringen.

La oss for eksempel flytte “brød” fra toppen av kunden favoritter listen til bunnen av listen:

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

De modifiserte kundeopplysningene etter bevege seg operasjonen vil være:

{"id": "1", "telephone": "001-555-5678", "favourites": ["Melk", "Egg", "Brød"], "communicationPreferences": null} 

De / favoritter / 0 og / favoritter / - i eksemplet ovenfor er JSON-pekere til start- og sluttindeksene til favoritter array.

4.5. De kopiere Operasjon

De kopiere operasjonen kopierer verdien på det angitte stedet til målplasseringen.

La oss for eksempel duplisere "Melk" i favoritter liste:

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

De modifiserte kundeopplysningene etter kopiere operasjonen vil være:

{"id": "1", "telephone": "001-555-5678", "favourites": ["Melk", "Egg", "Brød", "Melk"], "communicationPreferences": null}

4.6. De test Operasjon

De test operasjonen tester at verdien på "banen" er lik "verdien". Fordi PATCH-operasjonen er atomisk, bør PATCH-en kastes hvis noen av dens operasjoner mislykkes. De test operasjonen kan brukes til å validere at forutsetningene og etterbetingelsene er oppfylt.

La oss for eksempel teste at oppdateringen til kundens telefon feltet har vært vellykket:

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

La oss nå se hvordan vi kan bruke de ovennevnte konseptene i vårt eksempel.

5. HTTP PATCH-forespørsel ved bruk av JSON Patch Format

Vi kommer tilbake til vår Kunde brukstilfelle.

Her er HTTP PATCH-forespørselen om å utføre en delvis oppdatering til kundens telefon og favoritter liste med JSON Patch-format:

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

Viktigst, den Innholdstype for JSON Patch-forespørsler er applikasjon / json-patch + json. Forespørselslegemet er også en rekke JSON Patch-operasjonsobjekter:

[{"op": "erstatt", "sti": "/ telefon", "verdi": "+ 1-555-56"}, {"op": "legg til", "sti": "/ favoritter / 0 "," value ":" Brød "}]

Hvordan vil vi behandle en slik forespørsel på serversiden?

En måte er å skrive et tilpasset rammeverk som evaluerer operasjonene sekvensielt og bruker dem på målressursen som en atomenhet. Det er klart at denne tilnærmingen høres komplisert ut. Det kan også føre til en ikke-standardisert måte å konsumere oppdateringsdokumenter på.

Heldigvis trenger vi ikke å håndtere behandlingen av JSON Patch-forespørsler.

Java API for JSON Processing 1.0, eller JSON-P 1.0, opprinnelig definert i JSR 353, introduserte støtte for JSON Patch i JSR 374. JSON-P API gir JsonPatch skriv for å representere JSON Patch-implementeringen.

Imidlertid er JSON-P bare et API. For å jobbe med JSON-P API, må vi bruke et bibliotek som implementerer det. Vi bruker et slikt bibliotek kalt json-patch for eksemplene i denne artikkelen.

La oss nå se på hvordan vi kan bygge en REST-tjeneste som bruker HTTP PATCH-forespørsler ved hjelp av JSON Patch-formatet beskrevet ovenfor.

6. Implementering av JSON Patch i en Spring Boot-applikasjon

6.1. Avhengigheter

Den siste versjonen av json-patch kan bli funnet fra Maven Central repository.

Til å begynne med, la oss legge til avhengighet til pom.xml:

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

La oss nå definere en skjemaklasse som skal representere Kunde JSON-dokument:

offentlig klasse kunde {privat streng-id; privat streng telefon; private Favoritter på listen; privat KartkommunikasjonPreferanser; // standard getters og setters}

Deretter ser vi på vår kontrollermetode.

6.2. REST-kontrolleringsmetoden

Deretter kan vi implementere HTTP PATCH for vår kundebruk:

@PatchMapping (sti = "/ {id}", forbruker = "applikasjon / json-patch + json") offentlig ResponseEntity updateCustomer (@PathVariable String id, @RequestBody JsonPatch patch) {prøv {Customer customer = customerService.findCustomer (id) .orElseThrow (CustomerNotFoundException :: new); Customer customerPatched = applyPatchToCustomer (oppdatering, kunde); customerService.updateCustomer (customerPatched); returner 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 (); }} 

La oss nå forstå hva som skjer i denne metoden:

  • Til å begynne med bruker vi @PatchMapping kommentar for å markere metoden som en PATCH-behandlermetode
  • Når en lappeforespørsel med applikasjon / json-patch + json "Content-Type" ankommer, Spring Boot bruker standard MappingJackson2HttpMessageConverter for å konvertere forespørselens nyttelast til en JsonPatch forekomst. Som et resultat vil vår kontrollermetode motta forespørselsorganet som en JsonPatch forekomst

Innenfor metoden:

  1. Først kaller vi customerService.findCustomer (id) metode for å finne kundeposten
  2. Deretter, hvis kundeposten er funnet, påkaller vi ApplyPatchToCustomer (oppdatering, kunde) metode. Dette gjelder JsonPatch til kunden (mer om dette senere)
  3. Vi påkaller deretter customerService.updateCustomer (customerPatched) for å lagre kundeposten
  4. Til slutt returnerer vi a 200 OK svar til klienten med lappet Kunde detaljer i svaret

Viktigst, den virkelige magien skjer i ApplyPatchToCustomer (oppdatering, 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 å begynne med har vi vår JsonPatch forekomst som inneholder listen over operasjoner som skal brukes på målet Kunde
  2. Vi konverterer deretter målet Kunde inn i en forekomst av com.fasterxml.jackson.databind.JsonNode og gi den til JsonPatch.apply metode for å påføre plasteret. Bak kulissene, den JsonPatch.apply tar for seg å bruke operasjonene på målet. Resultatet av lappen er også et com.fasterxml.jackson.databind.JsonNode forekomst
  3. Vi kaller deretter objectMapper.treeToValue metode, som binder dataene i den oppdaterte com.fasterxml.jackson.databind.JsonNode til Kunde type. Dette er vår lappete Kunde forekomst
  4. Til slutt returnerer vi den lappete Kunde forekomst

La oss nå kjøre noen tester mot API-en vår.

6.3. Testing

Til å begynne med, la oss opprette en kunde ved hjelp av en POST-forespørsel til API: et:

krøll -i -X ​​POST // localhost: 8080 / kunder -H "Innholdstype: applikasjon / json" -d '{"telefon": "+ 1-555-12", "favoritter": ["Melk", "Egg"], "communicationPreferences": {"post": true, "email": true}} ' 

Vi mottar en 201 Opprettet respons:

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

De plassering svarhode er satt til plasseringen av den nye ressursen. Det indikerer at id av det nye Kunde er 1.

Deretter, la oss be om en delvis oppdatering til denne kunden ved hjelp av en PATCH-forespørsel:

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

Vi mottar en 200OK svar med oppdaterte kundeopplysninger:

HTTP / 1.1 200 Innholdstype: application / json Transfer-Encoding: chunked Date: Fri, 14 Feb 2020 21:23:14 GMT {"id": "1", "telephone": "+ 1-555-56" , "favorites": ["Bread", "Milk", "Eggs]]," communicationPreferences ": {" post ": true," email ": true}}

7. Konklusjon

I denne artikkelen så vi på hvordan du implementerer JSON Patch i REST APIer for våren.

Til å begynne med så vi på HTTP PATCH-metoden og dens evne til å utføre delvise oppdateringer.

Vi så på hva som er JSON Patch og forsto de forskjellige JSON Patch-operasjonene.

Til slutt diskuterte vi hvordan vi skulle håndtere en HTTP PATCH-forespørsel i en Spring Boot-applikasjon ved hjelp av json-patch-biblioteket.

Som alltid er kildekoden for eksemplene som brukes i denne artikkelen tilgjengelig på GitHub.


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