Kilka porad na temat usług REST

O usługach REST, które dzisiaj są wszechobecne pisałem już wiele razy np. tutaj.  Dzisiaj chciałbym napisać krótkie podsumowanie w formie porad i antywzorców. Zaczynamy:

1. Nigdy nie używaj czasowników w URI.

Przykład błędnych linków:

GET: localhost\persons\1\UpdateEmail?email=’…’

Jedynym dozwolonym czasownikiem w adresie to HTTP verb. Całość linku to nic innego jak hierarchia zasobów. Poprawna aktualizacja adresu email może wyglądać zatem następująco:

PUT: localhost\persons\1\email

Metoda PUT oznacza, że mamy do czynienia z modyfikacją danych. UpdateEmail to nazwa metody, a nie zasobu co jest sprzeczne z REST. Adres email’a w przypadku PUT można umieścić w ciele zapytania.

Analogicznie jeśli chcemy odczytać dane osoby, nie powinniśmy:

GET localhost\persons\1\getdata

Poprawny adres to:

GET localhost\persons\1\data

2. REST != RPC.  

Osoby zaczynające z REST, często próbują korzystać z tego typu usług tak samo jak np. z WCF. Klasyczne RPC (Remote-Procedure-Call) polega na wykonaniu konkretnej metody na usłudze. REST to hierarchia zasobów  więc powinniśmy tworzyć linki w postaci:

localhost/persons/1/address/town

Widzimy, że operujemy tutaj na kilku poziomach. Niepoprawną z kolei postacią jest:

localhost/persons/gettown?id=1

Wynika to nie tylko z użycia czasownika w nazwie, ale również w operowaniu bezpośrednio na korzeniu zasobów, zamiast na wykorzystaniu całej dostępnej hierarchii.

3. Korzystaj z dostępnych metod  HTTP.

Jeśli chcemy usunąć zasób wtedy:

DELETE local/host/persons/1

Początkujące osoby zbyt często korzystają wyłącznie z GET. Jeśli usługa ma realizować zadania CRUD, wtedy zdecydowanie potrzebujemy POST,GET,PUT,DELETE.

4. Korzystaj z dostępnych statusów HTTP.

Status 200 (OK) zdecydowanie nie jest jedynym z którego możemy korzystać. Jeśli operacja nie uda się, wtedy oprócz zwrócenia błędu w ciele HTTP, należy zwrócić również kod np. 500 (Internal Error) albo 400 (Bad Request) w zależności od kontekstu. Kody od 400 to błędy spowodowane przez klienta (np. nieprawidłowe zapytanie), z kolei od 500 to błędy spowodowane przez serwer.

Jeśli tworzymy nową encję za pomocą HTTP POST, można zwrócić 201 (Created) zamiast po prostu 200 (OK), który bardziej nadaję się na zapytania HTTP GET.

Inny przykład to kod 404 (Not found). Jeśli użytkownik wywoła localhost/persons/5, a osoba o identyfikatorze 5 nie istnieje, wtedy zamiast 200 należy zwrócić kod 404 .

5. QueryString

Klasyczne parametry QueyString wciąż są dozwolone, ale nie powinny określać one zasobów. Innymi słowy, złą praktyką jest:

localhost/persons?id=1

Identyfikator w tym przypadku jest ściśle powiązany z zasobem. Dopuszczalne jest za to używanie QueryString do określenia np. sortowania:

lcoalhost/persons?sort=desc

Podobnie sprawa wygląda z filtrowaniem czy z innymi parametrami, które nie określają zasobów a po prostu np. ich sposób wyświetlania.

6. Zwrócenie stanu obiektu po aktualizacji.

Utworzenie zasobu lub jego aktualizacja (POST, PUT) powinny zwracać jego reprezentacje albo link, który umożliwia odczytanie pełnego stanu. Innymi słowy, po utworzeniu zasobu, ciało odpowiedzi nie może być puste. Zwykle zwraca się mapę linków\operacji, które można wykonać na nowo utworzonym zasobie.

7.  Usługa powinna być bezstanowa.

Umożliwia to łatwiejsze skalowanie jak i cachowanie. Oznacza to, że wywołanie danej akcji, nie powinno zależeć od wykonania wcześniejszych operacji. Oczywiście mowa o stanie usługi, a nie aplikacji, gdzie stan stanowi zestaw reguł biznesowych. Z tego względu, autoryzacja nie powinna bazować na ciasteczkach czy sesjach ponieważ łamią one tą zasadę. Lepiej przesyłać dany token w każdym zapytaniu. Innymi słowy, każde zapytanie powinno dostarczyć wszystkie niezbędne dane do wykonania akcji.

8 thoughts on “Kilka porad na temat usług REST”

  1. W punkcie 3 (Korzystaj z dostępnych metod HTTP) wypisałeś
    POST,GET,POST,DELETE
    powinno być
    POST,GET,PUT,DELETE.

  2. Inny przykład to kod 204 (No content). Jeśli użytkownik wywoła localhost/persons/5, a osoba o identyfikatorze 5 nie istnieje, wtedy zamiast 200 należy zwrócić kod 204.

    204 to kod No content oznaczający, że żądanie zostało wykonane poprawnie (czyli obiekt był, bo inaczej jak żądanie wykonać poprawnie?), ale serwer nie musi przesyłać nic w odpowiedzi. Klasycznym przykładem jest odpowiedź na żądanie DELETE. Wtedy 204 pasuje. Bo po usunięciu, nic już nie ma do przesłania.

    Przy braku obiektu nie myślałeś przypadkiem o kodzie 404 Not found?

  3. Inny przykład to kod 204 (No content). Jeśli użytkownik wywoła localhost/persons/5, a osoba o identyfikatorze 5 nie istnieje, wtedy zamiast 200 należy zwrócić kod 204.

    204 to kod No content oznaczający, że żądanie zostało wykonane poprawnie (czyli obiekt był, bo inaczej jak żądanie wykonać poprawnie?), ale serwer nie musi przesyłać nic w odpowiedzi. Klasycznym przykładem jest odpowiedź na żądanie DELETE. Wtedy 204 pasuje. Bo po usunięciu, nic już nie ma do przesłania.

    Przy braku obiektu nie myślałeś przypadkiem o kodzie 404 Not found?

  4. @rbl, Zgadza sie. Powinien zostac zwrocony 404 not found w tym przypadku. Dzieki za wskazanie bledu! Poprawione:)

  5. Co do pierwszego punktu – to pieknie brzmi w trywialnych przykladach. Co jesli jakis link ma wykonac jakas skomplikowana akcje (np odwrocenie balansu konta powiazane z jego zamknieciem i wywolaniem 3 innych akcji na jakis innych grupach obiektow – nie wazne czy ma to sens, chodzi o to ze jest sporo nietrywialnych akcji, ktore ciezko jest przedstawic uzywajac rzeczownikow + kilku czasownikow z protokolu http). Oczywiscie sa sposoby aby zrobic to za pomoca rzeczownika i post’a ale zaczyna to byc malo czytelne kiedy porownuje sie ta ze starym soap.

  6. Marku,

    “Making your URLs refer to nouns is not a REST constraint, it is about encouraging people to fall into the pit of success”
    http://stackoverflow.com/questions/2173721/why-does-including-an-action-verb-in-the-uri-in-a-rest-implementation-violate-th

    Moja sugestia to się trzymać Podstaw REST dla CRUDa, a inne akcje zebrać pod POST zasob/actions/CosTam?param0=x&param1=y

    Kolejnym problemem, będzie generowanie linków do raportów, itp… bo te muszą być GETem, a często będą zawierać dużo zhierarchizowanych parametrów + access_token. wtedy ja upycham w jsona, encoduje i upycham w query stringa i z tego robie link. Alternatywnie zamiast JSON można jakiś własny format przyjazny urlom złożyć.

  7. Napisałeś “Z tego względu, autoryzacja nie powinna bazować na ciasteczkach czy sesjach ponieważ łamią one tą zasadę”

    W bierniku piszęmy tę. Czyli tę zasadę.

Leave a Reply

Your email address will not be published.