HTTP PUT vs HTTP PATCH i et REST API
1. Oversikt
I denne raske artikkelen ser vi på forskjeller mellom HTTP PUT- og PATCH-verbene og på semantikken til de to operasjonene.
Vi bruker Spring til å implementere to REST-endepunkter som støtter disse to typer operasjoner, og for å bedre forstå forskjellene og den riktige måten å bruke dem på.
2. Når skal jeg bruke Put og When Patch?
La oss starte med en enkel og litt enkel uttalelse.
Når en klient trenger å erstatte en eksisterende ressurs helt, kan de bruke PUT. Når de gjør en delvis oppdatering, kan de bruke HTTP PATCH.
For eksempel, når du oppdaterer et enkelt felt i ressursen, kan det være tungvint å sende den komplette ressursrepresentasjonen og bruke mye unødvendig båndbredde. I slike tilfeller gir semantikken til PATCH mye mer mening.
Et annet viktig aspekt å vurdere her er egenmakt; PUT er idempotent; PATCH kan være, men det er ikke nødvendig. Og så - avhengig av semantikken til operasjonen vi implementerer, kan vi også velge den ene eller den andre basert på denne karakteristikken.
3. Implementering av PUT- og PATCH-logikk
La oss si at vi vil implementere REST API for oppdatering av en HeavyResource med flere felt:
offentlig klasse HeavyResource {private heltal id; privat strengnavn; privat strengadresse; // ...
Først må vi lage endepunktet som håndterer en fullstendig oppdatering av ressursen ved hjelp av PUT:
@PutMapping ("/ heavyyresource / {id}") public ResponseEntity saveResource (@RequestBody HeavyResource heavyResource, @PathVariable ("id") Streng-id) {heavyResourceRepository.save (heavyResource, id); returner ResponseEntity.ok ("ressurs lagret"); }
Dette er et standard sluttpunkt for oppdatering av ressurser.
La oss si at adressefeltet ofte blir oppdatert av klienten. I så fall, vi vil ikke sende helheten HeavyResource objekt med alle felt, men vi ønsker muligheten til å bare oppdatere adresse felt - via PATCH-metoden.
Vi kan lage en HeavyResourceAddressOnly DTO for å representere en delvis oppdatering av adressefeltet:
offentlig klasse HeavyResourceAddressOnly {private Integer id; privat strengadresse; // ...}
Deretter kan vi utnytte PATCH-metoden for å sende en delvis oppdatering:
@PatchMapping ("/ heavyyresource / {id}") offentlig ResponseEntity partialUpdateName (@RequestBody HeavyResourceAddressOnly partialUpdate, @PathVariable ("id") Streng-id) {heavyResourceRepository.save (partialUpdate, id); returner ResponseEntity.ok ("ressursadresse oppdatert"); }
Med denne mer detaljerte DTO-en kan vi bare sende feltet vi trenger å oppdatere - uten overhead for å sende hele HeavyResource.
Hvis vi har et stort antall av disse delvise oppdateringsoperasjonene, kan vi også hoppe over opprettelsen av en tilpasset DTO for hver ut - og bare bruke et kart:
@RequestMapping (verdi = "/ heavyyresource / {id}", metode = RequestMethod.PATCH, forbruker = MediaType.APPLICATION_JSON_VALUE) offentlig ResponseEntity partialUpdateGeneric (@RequestBody Map oppdateringer, @PathVariable ("id") String-id) {heavyResourceReport oppdateringer, id); returner ResponseEntity.ok ("ressurs oppdatert"); }
Denne løsningen vil gi oss mer fleksibilitet i implementering av API; men vi mister også noen få ting - for eksempel validering.
4. Testing PUT og PATCH
Til slutt, la oss skrive tester for begge HTTP-metodene. Først vil vi teste oppdateringen av hele ressursen via PUT-metoden:
mockMvc.perform (put ("/ heavyyresource / 1") .contentType (MediaType.APPLICATION_JSON_VALUE) .content (objectMapper.writeValueAsString (new HeavyResource (1, "Tom", "Jackson", 12, "himmelsgate")))) .andExpect (status (). isOk ());
Utførelse av en delvis oppdatering oppnås ved å bruke PATCH-metoden:
mockMvc.perform (patch ("/ heavyyrecource / 1") .contentType (MediaType.APPLICATION_JSON_VALUE) .content (objectMapper.writeValueAsString (new HeavyResourceAddressOnly (1, "5th avenue")))). og Expect (status () isO). );
Vi kan også skrive en test for en mer generisk tilnærming:
HashMap-oppdateringer = nye HashMap (); updates.put ("adresse", "5. aveny"); mockMvc.perform (patch ("/ heavyyresource / 1") .contentType (MediaType.APPLICATION_JSON_VALUE) .content (objectMapper.writeValueAsString (updates))). andExpect (status (). isOk ());
5. Håndtering av delvise forespørsler med Null Verdier
Når vi skriver en implementering for en PATCH-metode, må vi spesifisere en kontrakt om hvordan vi skal behandle saker når vi får det null som en verdi for adresse felt i HeavyResourceAddressOnly.
Anta at klienten sender følgende forespørsel:
{"id": 1, "address": null}
Da kan vi håndtere dette som å sette en verdi av adresse felt til null eller bare ignorere en slik forespørsel ved å behandle den som ingen endring.
Vi bør velge en strategi for håndtering null og hold deg til det i hver implementering av PATCH-metoden.
6. Konklusjon
I denne raske opplæringen fokuserte vi på å forstå forskjellene mellom HTTP PATCH og PUT-metodene.
Vi implementerte en enkel Spring REST-kontroller for å oppdatere en ressurs via PUT-metode og en delvis oppdatering ved hjelp av PATCH.
Implementeringen av alle disse eksemplene og kodebitene finnes i GitHub-prosjektet - dette er et Maven-prosjekt, så det skal være enkelt å importere og kjøre som det er.