HTTP: PUT vs. POST vs. PATCH

21 Okt

Als ich gerade dabei war, einige interessante Passagen im Buch „REST in Practice: Hypermedia and Systems Architecture“ von Jim Webber zu lesen, hat eine kleine Infobox auf Seite 114 mein Verständnis der HTTP-Methoden PUT und POST wieder durcheinandergebracht.

Auch wenn es schon viele Artikel dazu im Web gibt, hier nochmal die Unterscheidung zwischen PUT und POST:

Zwei wichtige Begrifflichkeiten im Voraus:
Eine HTTP-Methode wird als sicher bezeichnet, wenn ihre Ausführung serverseitig keine Änderung hervorruft (Ein GET ist sicher). Falls der mehrmalige Aufruf einer Methode dieselben Seiteneffekte bewirkt, wie der einmalige, handelt es sich um eine idempotente Methode.

Die POST-Methode dient zur Erstellung einer Ressource bei serverseitiger URL-Vergabe. Ein typischer Anwendungsfall ist die Ausführung auf einer Listenressource (hier:user), wodurch der Liste eine neue Ressource hinzugefügt wird.

# HTTP-Anfrage
POST /user HTTP/1.1
Host: example.org

{
name:“Franz“,
alter:“24″,
mail:“franz@example.org“
}
# HTTP-Antwort
HTTP/1.1 201 Created
Content-Type: application/json
Location: http://www.example.org/user/7689

Der Server hat für uns einen neuen User angelegt, der nun unter http://www.example.org/user/7689 abrufbar ist.
POST ist weder sicher noch idempotent. Wenn wir die obige Anfrage mehrmals ausführen, erstellen wir mehrere User mit dem Namen Franz aber mit unterschiedlichen IDs.

Mit PUT wird eine Ressource aktualisiert oder, falls sie noch nicht existiert, erstellt. Dabei ist zu beachten, dass sich die Operation direkt auf die Ressource auswirkt, deren URL Ziel der Anfrage ist.

# HTTP-Anfrage
PUT /user/745 HTTP/1.1
Host: example.org
Content-Type: application/json

{
name:“Franz“,
alter:“24″,
mail:“franz@example.org“
}

Wir kennen hier also schon die ID des Users und „putten“ hierhin. PUT ist idempotent. Der mehrmalige Aufruf verändert die Ressource nicht.

Nun das Wichtige: Laut Spezifikation wird die Ressource unter http://www.example.org/user/745 KOMPLETT durch die Informationen im HTTP-Body ersetzt. PUT ist NICHT für inkrementelle Updates gedacht.

Das ist im obigen Beispiel irrelevant aber für einen RESTful Service, der Ressourcen untereinander verknüpft, kommt es zu einem Problem:

# HTTP-Anfrage
GET /user/745 HTTP/1.1
Host: example.org
# HTTP-Antwort
HTTP/1.1 200 OK
Content-Type: application/json

{
name:“Franz“,
alter:“24″,
mail:“franz@example.org“,
„links“ : [{
„rel“ : „self“,
„href“ : „http://example.org/user/745“
}, {
„rel“ : „profile“,
„href“ : „http://example.org/user/745/profile“,
}]
}

Diese User-Repräsentation enthält nun Links auf sich selbst und zum Profil von Franz. Wenn Franz nun Geburtstag hat und wir sein Alter erhöhen wollen, müssten wir bei einem PUT die komplette Repräsentation inkl. Links mitschicken:

# HTTP-Anfrage
PUT /user/745 HTTP/1.1
Host: example.org
Content-Type: application/json

{
name:“Franz“,
alter:“25„,
mail:“franz@example.org“,
„links“ : [{
„rel“ : „self“,
„href“ : „http://example.org/user/745“
}, {
„rel“ : „profile“,
„href“ : „http://example.org/user/745/profile“,
}]
}

Das „fühlt sich komisch an“, weil der Client an den Links ja gar nicht interessiert ist, sondern nur an den „direkten Nutzdaten“.

Zwei Lösungsmöglichkeiten gibt es:

  • Jim Webber nutzt in seinem Buch in solchen Situationen immer POST statt PUT und schickt keine Links mit. Aktuell ist dies wahrscheinlich die beste Lösung.
  • Die Internet Engineering Task Force hat hierfür bereits im März 2010 eine neue HTTP-Methode für inkrementelle Updates standardisiert: PATCH. Diese Methode ist aber bis jetzt kaum bekannt und verbreitet.

Was nun die beste Möglichkeit für die ginkgo-API ist, werde ich anhand der technischen Möglichkeiten in Rails festmachen. Generell ist solch eine API Entwicklung aber tatsächlich ein Ringen zwischen Standards und Machbarkeit.

4 Antworten to “HTTP: PUT vs. POST vs. PATCH”

  1. wollepb 23. Oktober 2011 um 14:21 #

    Verständnisfrage: wenn ich das erste Mal auf eine Ressource putte, dann ändert sie sich doch. Wenn ich danach mehrmals das gleiche putte, ändert sie sich nicht mehr (außer ich habe so was wie last-changed o.ä.). Darf man dann trotzdem von idempotent sprechen?

    • chrisupb 24. Oktober 2011 um 17:22 #

      Hmm die Frage passt irgendwie nicht ;-)

      Vielleicht hilft das:
      GET ist sicher UND idempotent, weil Daten nicht und auch nicht bei mehreren Aufrufen verändert werden.

      PUT ist NICHT sicher aber idempotent, weil Daten auf jeden Fall (beim 1. Mal) verändert werden aber bei den darauffolgenden Malen nicht mehr.

      POST ist weder sicher noch idempotent, weil Daten jedes Mal verändert werden.

Trackbacks/Pingbacks

  1. Rails 3.2 und PATCH « Studentenblogs DDI@UPB - 16. Dezember 2011

    […] darüber, ob Rails 3.2 die neue HTTP-Methode PATCH unterstützen soll (vgl. auch meinen Blogeintrag). Ergebnisse gibt es nicht wirklich. Wegen der vielen unterschiedlichen Meinungen, wird dabei auch […]

  2. Ginkgo-API: Ressourcenstruktur und Aufbau von Repräsentationen « Studentenblogs DDI@UPB - 30. Dezember 2011

    […] Aktualisierungen von Ressourcen hatte ich ursprünglich auch POST vorgesehen (vgl. mein Blogpost). Dann funktioniert das automatische Routing von Rails aber nicht mehr, das ja PUT nutzt, um an die […]

Schreibe einen Kommentar

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s

%d Bloggern gefällt das: