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.


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