Ciekawe metody HTTP – część 1

Tworząc serwisy RESTowe myślimy o różnych metodach HTTP. Oprócz standardych GET, POST, PUT, DELETE protokół daje nam dużo innych opcji. Aby nasze API było w pełni RESTfull poznamy dziś mniej znane metody HTTP.

OPTIONS czyli dzień dobry, co słychać?

Zaczynam od tej metody z kilku powodów. OPTIONS jest swoistym przywitaniem się z serwisem i zapytaniem o nasze możliwości. Niestety prawie nikt jej nie implementuje.

Metodą tą pytamy się serwera o to, co możemy zrobić z zasobem. Jakie metody wywołać, jakich danych się spodziewać. Przykładowo wywołując:

$ curl -X OPTIONS -i http://moj_serwis_rest/zasoby/zasob_1

Serwer powinien nam powiedzieć co to za zasób i co możemy z nim zrobić:

HTTP/1.1 200 OK
Server: Apache
Allow: HEAD,GET,PUT,DELETE,OPTIONS
Content-Length: 0

Wiemy już jakie metody możemy wywoływać wobec naszego zasobu. Ale to nie wszystko! Serwer w odpowiedzi na OPTIONS może zwrócić nam treść.

Nie będze to jednak treść strony czy zawartość serwisu lecz opis jak traktować kolejne metody. Format opisu jest dowolny (specyfikacja nie narzuca). Możemy (my jako API) w tym miejscu zwrócić dokumentację do wywołań innych metod np. w formacie html:

HTTP/1.1 200 OK
Server: Apache
Allow: HEAD,GET,PUT,DELETE,OPTIONS
Content-Length: 12345
Content-Type: text/html;charset=ISO-8859-1
<html ... tu treść dokumentacji ...

Nic nie stoi na przeszkodzie, żeby zwrócić dokumentację w innych formatach, np. application/pdf czy nawet jako dokument ms-word.

Specyfikacja mówi, że klient nie powinien cacheować wyników metody OPTIONS. Mogą się one zmieniać, np. zapis (POST) może być dostępny zależnie od autoryzacji itp.

HEAD czyli prawie GET

Kolejna ciekawa metoda to HEAD. Ta metoda powinna zwrócić dokładnie to samo co zwróciłby w tym miejscu GET z ty wyjątkiem, że nie podaje zawartości. HEAD służy nam tylko do odpytania się o nagłówki HTTP.

Po co taka metoda? Np po to, żeby sprawdzać czy zapisane linki do zasobów nadal działają. Po to aby sprawdzać, czy nie musimy zaktualizować cache. Można też wstępnie badać zasób metodą HEAD jeśli chcemy dowiedzieć się jak dużych danych się spodziewać.

Warunkowy GET

A jednak będzie o GET, ale o mało znanych jego możliwościach. Możemy zażądać od serwera zasobów pod warunkiem że…

Nagłówek If-Modified-Since pozwala nam kontrolować co przechowujemy w naszym cache. Jeśli zapisaliśmy sobie kopię zasobu dnia X to możemy zażądać, aby serwer dał nam zasób ale tylko gdy został on zmieniony:

$ curl -i http://moj_serwis_rest/zasoby/zasob_1 \
-H "If-Modified-Since: Mon, 1 Jul 2014 19:43:31 GMT"

Jeśli zasób się zmieni, serwer zwróci go normalnie. Jeśli jednak nie było żadnych zmian to zamiast zasobu powinniśmy dostać odpowiedź 304 (nie zmodyfikowano).

Podobnie działa nagłówek If-Unmodified-Since, który zwraca dane jeśli nie były zmienione lub kod 412 (warunek nie spełniony).

Mamy również warunkowe metody If-Match itp, które korzystają z e-tagów HTTP. Sam mechanizm e-tagów jest dobrym tematem na osobny wpis.

Kiedy POST a kiedy PUT?

Niektórzy programiści czują się niepewnie decydując o wyborze jednej z tych metod. Wiemy, że jedna dodaje nowy zasób a druga aktualizuje. A gdy jeszcze pod nogami zacznie się nam plątać metoda PATCH, zamieszanie gotowe.

Tymczasem wystarczy spędzić chwilę ze specyfikacją HTTP aby dowiedzieć się, że:

Nowe zasoby wkładamy metodą POST gdy nie znamy ich docelowego adresu. Co więcej, powinniśmy ją wysłać na adres, który jest nadrzędny wobec nowo tworzonego zasobu. Przykładowo mamy listę artykułów pod adresem http://moj_serwis_rest/artykuly/. Na ten adres powinniśmy wysłać żądanie w stylu:

$ curl -X POST -d "Tutaj treść artykułu" http://moj_serwis_rest/artykuly/

Takie wywołanie powinno nam zwrócić odpowiedź 201 (utworzono). Razem z nią powinniśmy też otrzymać adres utworzonego zasobu (np. http://moj_serwis_rest/artykuly/nowy_artykul/). Jeśli jednak serwis nie udostępnia odczytu (np serwer logów, pozwala je tylko zapisywać) to API zwróci nam 200 (ok) lub 202 (brak treści).

Metoda POST przypomina trochę fabrykę w programowaniu obiektowym. Możemy pobrać z fabryki listę dostępnych obiektów albo zażądać utworzenia nowego.

Jeśli znamy adres zasobu, nawet gdy on jeszcze nie istnieje, używamy metody PUT. Możemy wtedy nie znać żadnej listy, kolekcji czy innego nadrzędnego zasobu. Po prostu chcemy aby nasz zasób znalazł się pod podanym adresem:

$ curl -X PUT -d "Treść, którą wkładamy" http://moj_serwis_rest/zasoby/mój_zasób

Jeśli pod podanym adresem już coś jest, powinno zostać całkiem zastąpione. Jeśli nic nie ma, powinno zostać utworzone.

Podobnie jak przy POST serwer może zwrócić 201 (utworzono) itp. Serwer może też bronić się przed zaakceptowaniem naszego adresu, wtedy może odpowiedzieć 301 (przeniesiono na stałe w inne miejsce).

Możemy myśleć o metodzie PUT jak o funkcji save() w ORM. Tworzymy nowy obiekt albo od zera albo poprzez pobranie go z bazy. Potem po modyfikacjach mówimy save() czyli chcemy, żeby obiekt znalazł się w bazie, nieważne czy wcześniej w niej był czy nie.

Co dalej?

W kolejnej części zajmę się jeszcze bardziej niszowymi metodami HTTP. W tym też takimi, które wykraczają poza oficjalną specyfikację.

Póki co warto czytać właśnie specyfikację HTTP.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *