HTTP PUT vs HTTP PATCH u REST API-ju

1. Pregled

U ovom kratkom članku promatramo razlike između glagola HTTP PUT i PATCH te semantiku dviju operacija.

Proljeće ćemo koristiti za implementaciju dviju krajnjih točaka REST koje podržavaju ove dvije vrste operacija te za bolje razumijevanje razlika i ispravan način njihove upotrebe.

2. Kada koristiti put i kada zakrpu?

Počnimo s jednostavnom i malo jednostavnom izjavom.

Kada klijent treba u potpunosti zamijeniti postojeći resurs, može koristiti PUT. Kad rade djelomično ažuriranje, mogu koristiti HTTP PATCH.

Na primjer, kada ažurirate jedno polje Resursa, slanje cjelovite reprezentacije Resursa može biti glomazno i ​​koristi puno nepotrebne propusnosti. U takvim slučajevima semantika PATCH-a ima puno više smisla.

Sljedeći važan aspekt koji treba ovdje razmotriti je idempotencija; PUT je idempotentan; PATCH može biti, ali nije potreban. I, tako - ovisno o semantici operacije koju provodimo, također možemo odabrati jedno ili drugo na temelju ove karakteristike.

3. Implementacija logike PUT i PATCH

Recimo da želimo implementirati REST API za ažuriranje a HeavyResource s više polja:

javna klasa HeavyResource {private Integer id; privatni naziv niza; privatna string adresa; // ...

Prvo, moramo stvoriti krajnju točku koja obrađuje potpuno ažuriranje resursa pomoću PUT-a:

@PutMapping ("/ heavyresource / {id}") javni ResponseEntity saveResource (@RequestBody HeavyResource heavyResource, @PathVariable ("id") String id) {heavyResourceRepository.save (heavyResource, id); vratiti ResponseEntity.ok ("resurs spremljen"); }

Ovo je standardna krajnja točka za ažuriranje resursa.

Recimo sada da će klijent često ažurirati to polje adrese. U tom slučaju, ne želimo poslati cjelinu HeavyResource objekt sa svim poljima, ali želimo mogućnost ažuriranja samo adresa polje - metodom PATCH.

Možemo stvoriti HeavyResourceAddressOnly DTO predstavlja djelomično ažuriranje polja adrese:

javna klasa HeavyResourceAddressOnly {privatni cjeloviti id; privatna string adresa; // ...}

Dalje, možemo koristiti metodu PATCH za slanje djelomičnog ažuriranja:

@PatchMapping ("/ heavyresource / {id}") javni ResponseEntity djelomičnoUpdateName (@RequestBody HeavyResourceAddressOnly activUpdate, @PathVariable ("id") String id) {heavyResourceRepository.save (djelomično ažuriranje, id); return ResponseEntity.ok ("adresa resursa ažurirana"); }

Ovim granuliranijim DTO-om možemo poslati samo polje koje trebamo ažurirati - bez dodatnih troškova slanja cijelog HeavyResource.

Ako imamo velik broj ovih djelomičnih operacija ažuriranja, također možemo preskočiti stvaranje prilagođenog DTO-a za svaki izlaz - i koristiti samo kartu:

@RequestMapping (value = "/ heavyresource / {id}", method = RequestMethod.PATCH, konzumira = MediaType.APPLICATION_JSON_VALUE) javni ResponseEntity partUpdateGeneric (@RequestBody Map Updates, @PathVariable ("id") String id) {heavyResourve (ID) String id )Repository. ažuriranja, id); vratiti ResponseEntity.ok ("resurs ažuriran"); }

Ovo rješenje pružit će nam veću fleksibilnost u implementaciji API-ja; međutim, gubimo i nekoliko stvari - poput provjere valjanosti.

4. Testiranje PUT-a i PATCH-a

Na kraju, napišimo testove za obje HTTP metode. Prvo želimo testirati ažuriranje punog resursa metodom PUT:

mockMvc.perform (put ("/ heavyresource / 1") .contentType (MediaType.APPLICATION_JSON_VALUE) .content (objectMapper.writeValueAsString (novi HeavyResource (1, "Tom", "Jackson", 12, "nebeska ulica"))) .andExpect (status (). isOk ());

Izvršenje djelomičnog ažuriranja postiže se metodom PATCH:

mockMvc.perform (patch ("/ heavyrecource / 1") .contentType (MediaType.APPLICATION_JSON_VALUE) .content (objectMapper.writeValueAsString (new HeavyResourceAddressOnly (1, "5th avenue")))) (status (Expect). );

Također možemo napisati test za općenitiji pristup:

Ažuriranja HashMap-a = novi HashMap (); updates.put ("adresa", "5. avenija"); mockMvc.perform (patch ("/ heavyresource / 1") .contentType (MediaType.APPLICATION_JSON_VALUE) .content (objectMapper.writeValueAsString (updates))) .andExpect (status (). isOk ()); 

5. Obrada djelomičnih zahtjeva s Nula Vrijednosti

Kada pišemo implementaciju za metodu PATCH, moramo navesti ugovor o postupanju sa slučajevima kada ih dobijemo null kao vrijednost za adresa polje u HeavyResourceAddressOnly.

Pretpostavimo da klijent pošalje sljedeći zahtjev:

{"id": 1, "adresa": null}

Tada to možemo podnijeti kao postavljanje vrijednosti adresa polje do null ili samo ignoriranje takvog zahtjeva tretirajući ga kao promjenu.

Trebali bismo odabrati jednu strategiju rukovanja null i pridržavajte se toga u svakoj implementaciji PATCH metode.

6. Zaključak

U ovom smo se brzom vodiču usredotočili na razumijevanje razlika između metoda HTTP PATCH i PUT.

Implementirali smo jednostavni kontroler Spring REST za ažuriranje resursa metodom PUT i djelomično ažuriranje pomoću PATCH-a.

Provedbu svih ovih primjera i isječaka koda možete pronaći u projektu GitHub - ovo je Maven projekt, pa bi ga trebalo lako uvesti i pokrenuti kakav jest.