HTTP PUT vs HTTP PATCH egy REST API-ban

áttekintés

ebben a gyors cikkben a HTTP PUT és a PATCH igék közötti különbségeket, valamint a két művelet szemantikáját vizsgáljuk.

a Spring segítségével két REST végpontot valósítunk meg, amelyek támogatják ezt a két típusú műveletet, és jobban megértjük a különbségeket és a helyes használat módját.

mikor kell használni a Put és mikor tapaszt?

kezdjük egy egyszerű, kissé egyszerű kijelentéssel.

amikor egy ügyfélnek teljesen le kell cserélnie egy meglévő erőforrást, használhatja a PUT-ot. Amikor részleges frissítést végeznek, használhatják a HTTP javítást.

például az erőforrás egyetlen mezőjének frissítésekor a teljes erőforrás-ábrázolás elküldése nehézkes lehet, és sok felesleges sávszélességet igényel. Ilyen esetekben a PATCH szemantikája sokkal értelmesebb.

egy másik fontos szempont, amelyet itt figyelembe kell venni, az idempotencia; a PUT idempotens; a javítás lehet, de nem szükséges. Tehát-a végrehajtott művelet szemantikájától függően-e tulajdonság alapján is választhatjuk az egyiket vagy a másikat.

PUT és PATCH logika implementálása

tegyük fel, hogy a REST API-t szeretnénk implementálni egy HeavyResource frissítéséhez több mezővel:

public class HeavyResource { private Integer id; private String name; private String address; // ...

először létre kell hoznunk azt a végpontot, amely az erőforrás teljes frissítését kezeli a PUT használatával:

@PutMapping("/heavyresource/{id}")public ResponseEntity<?> saveResource(@RequestBody HeavyResource heavyResource, @PathVariable("id") String id) { heavyResourceRepository.save(heavyResource, id); return ResponseEntity.ok("resource saved");}

ez egy szabványos végpont az erőforrások frissítéséhez.

tegyük fel, hogy a címmezőt gyakran frissíti az ügyfél. Ebben az esetben nem akarjuk elküldeni az egész HeavyResource objektumot az összes mezővel, de azt akarjuk, hogy csak a címmezőt frissítsük – a PATCH módszerrel.

létrehozhatunk egy Heavarresourceaddressonly DTO-t a cím mező részleges frissítéséhez:

public class HeavyResourceAddressOnly { private Integer id; private String address; // ...}

következő, kihasználhatjuk a PATCH módszert részleges frissítés küldésére:

@PatchMapping("/heavyresource/{id}")public ResponseEntity<?> partialUpdateName( @RequestBody HeavyResourceAddressOnly partialUpdate, @PathVariable("id") String id) { heavyResourceRepository.save(partialUpdate, id); return ResponseEntity.ok("resource address updated");}

ezzel a szemcsésebb DTO – val csak azt a mezőt küldhetjük el, amelyet frissítenünk kell-anélkül, hogy az egész HeavyResource küldésének költsége lenne.

ha nagyszámú ilyen részleges frissítési műveletünk van, akkor kihagyhatjuk az egyéni DTO létrehozását is minden egyes kimenethez – és csak térképet használhatunk:

@RequestMapping(value = "/heavyresource/{id}", method = RequestMethod.PATCH, consumes = MediaType.APPLICATION_JSON_VALUE)public ResponseEntity<?> partialUpdateGeneric( @RequestBody Map<String, Object> updates, @PathVariable("id") String id) { heavyResourceRepository.save(updates, id); return ResponseEntity.ok("resource updated");}

ez a megoldás nagyobb rugalmasságot biztosít számunkra az API megvalósításában; azonban néhány dolgot is elveszítünk – például az érvényesítést.

tesztelés és javítás

végül írjunk teszteket mindkét HTTP-módszerhez. Először a teljes erőforrás frissítését szeretnénk tesztelni PUT módszerrel:

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

a részleges frissítés végrehajtása a PATCH módszerrel érhető el:

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

írhatunk egy tesztet egy általánosabb megközelítéshez is:

HashMap<String, Object> updates = new HashMap<>();updates.put("address", "5th avenue");mockMvc.perform(patch("/heavyresource/1") .contentType(MediaType.APPLICATION_JSON_VALUE) .content(objectMapper.writeValueAsString(updates)) ).andExpect(status().isOk());

részleges kérések kezelése Null értékekkel

amikor egy PATCH metódus implementációját írjuk, meg kell adnunk egy szerződést arról, hogyan kezeljük azokat az eseteket, amikor null értéket kapunk a HeavyResourceAddressOnly címmezőjének értékeként.

tegyük fel, hogy az ügyfél a következő kérést küldi:

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

ezután kezelhetjük ezt úgy, hogy a címmező értékét nullára állítjuk, vagy csak figyelmen kívül hagyjuk az ilyen kérést úgy, hogy nem változtatunk.

ki kell választanunk egy stratégiát A null kezelésére, és ragaszkodnunk kell hozzá minden PATCH módszer végrehajtásakor.

következtetés

ebben a gyors oktatóanyagban a HTTP javítás és a PUT módszerek közötti különbségek megértésére összpontosítottunk.

egy egyszerű Spring REST vezérlőt implementáltunk egy erőforrás PUT módszerrel történő frissítéséhez, valamint egy részleges frissítést PATCH segítségével.

ezeknek a példáknak és kódrészleteknek a megvalósítása megtalálható a GitHub projektben – ez egy Maven projekt, így könnyen importálható és futtatható.

kezdje el a Spring 5 és a Spring Boot 2 használatával a Learn Spring tanfolyamon keresztül:

>> nézze meg a tanfolyamot

Vélemény, hozzászólás?

Az e-mail-címet nem tesszük közzé.