menu di navigazione del network

Le insidie di PUT e PATCH nella scrittura di API

Nella scrittura di API capita spesso di vedere gestite in maniera scorretta i metodi PUT e PATCH.
Anche sul web c’è un po’ di confusione causata da molti tutorial imprecisi e a volte dall’uso improprio che viene fatto delle specifiche HTTP anche nei framework di sviluppo.

Il lavoro di interoperabilità fortunatamente fa’ un po’ di chiarezza sul tema, partendo dalle basi.

HTTP assegna ad ogni metodo un significato ben preciso: tecnicamente questo significato viene chiamato “semantica”. Vediamo i due esempi più noti:

  • il metodo GET “scarica” una risorsa;
  • il metodo POST “processa” una richiesta secondo la semantica della risorsa;

Con POST l’implementatore definisce il comportamento della risorsa eg. https://api.example/library/v1/books: questo non è definito a priori e dev’essere esplicitamente indicato nella documentazione OpenAPI.
Possiamo usare POST quindi per creare, cancellare, modificare questa o altre risorse ma dobbiamo evitare di sovraccaricare di significati la risorsa per rendere l’API fruibile; a tal fine possiamo usare i metodi PUT e PATCH.

Il metodo PUT “sostituisce” una risorsa, creandola all’occorrenza; la specifica ci ricorda quindi che PUT rimpiazza la risorsa destinazione usando la rappresentazione contenuta nel payload body della richiesta. Prima regola quindi:

Usate PUT solo se volete SOSTITUIRE COMPLETAMENTE una risorsa.

PATCH richiede invece alcuni accorgimenti, perché questo metodo non è definito nelle nuove specifiche di HTTP/1.1 del 2014 ma nel precedente RFC 5789.

Come indicato in questa considerazione NON SI DOVREBBE associare un significato di patch a dei media-type che non lo prevedono (eg. application/json o application/xml) ma utilizzare dei media-type adeguati.

E’ possibile ad esempio usare application/merge-patch+json definito in RFC 7386 facendo attenzione:

  • che l’HTTP method PATCH rifiuti richieste con media-type non adeguato con HTTP status 415 Unsupported Media Type;
  • che il media-type di patching sia compatibile con gli schemi utilizzati;
  • di verificare le considerazioni di sicurezza presenti in RFC 7396#section-5 e RFC 5789#section-5

Vediamo un esempio di merge-patch+json dove:

  • la property a viene valorizzata a z;
  • la property c.f viene rimossa
    L’esempio chiarisce che questa specifica non permette di impostare una property a null.
       PATCH /target HTTP/1.1
       Host: example.org
       Content-Type: application/merge-patch+json

       {
         "a": "z",
         "c": { "f": null }
       }

Il medatype json-patch+json è più complesso del precedente ma copre più casi d’uso, comportandosi come un changelog:

  • se a.b.c == “foo” lo rimuove
  • imposta a.b.c = [“foo”, “bar”]
  • imposta a.b.c = 42
  • imposta a.b.d = 42 e rimuove a.b.c
  • imposta a.b.e = 42 e a.b.d = 42
   PATCH /my/data HTTP/1.1
   Host: example.org
   Content-Length: 326
   Content-Type: application/json-patch+json
   If-Match: "abc123"

   [
     { "op": "test", "path": "/a/b/c", "value": "foo" },
     { "op": "remove", "path": "/a/b/c" },
     { "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] },
     { "op": "replace", "path": "/a/b/c", "value": 42 },
     { "op": "move", "from": "/a/b/c", "path": "/a/b/d" },
     { "op": "copy", "from": "/a/b/d", "path": "/a/b/e" }
   ]

A tutti i curiosi, potete approfondire leggendo le specifiche o commentando questo post anche via https://slack.developers.italia.it

4 Mi Piace