poniedziałek, 1 czerwca 2009

RESTful webservices

w 2000 roku Roy Thomas Fielding opracował w swojej pracy doktorskiej ciekawy sposób realizowania wymiany komunikatów XML poprzez HTTP. Jego pomysł otrzymał już swoją specyfikację JAX-RS (JAX-311) i stał się częścią J2EE 6.
Aktualnie większość serwisów oparta jest na SOAP/WSDL i serwisy te działają - dlaczego więc REST miałby być lepszy? Dlaczego stał się standardem?

Rozszyfrujmy skrót REST: REpresentational State Transfer. REST opiera się przede wszystkim na tym, że każdy zasób w internecie ma swój unikalny identyfikator np.:

http://web-services.pl/klieci (lista wszystkich klientów)
http://web-services.pl/klient/34 (konkretny klient o identyfikatorze 34)
http://web-services.pl/zamowienia/2009/06 (wszystkie zamówienia z czerwca 2009)
http://web-services.pl/zamowienie/2009/06/1234 (konkretne zamówienie)

Użytkownik "chodząc" po aplikacji klika w linki, czego wynikiem jest kolejny ekran. Kolejne ekrany można określić jako nowy stan aplikacji - prezentowane są inne zasoby, lub te same, ale w inny sposób (np. zaktualizowane). Użytkownik ma więc wpływ na zmianę stanu tego, co aktualnie widzi. Stąd nazwa, której próba tłumaczenia mogłaby być taka: abstrakcyjna zmiana stanów.


Ponadto został wykorzystany fakt, że HTTP posiada m.in. takie metody jak: POST, GET, PUT, DELETE. Z kolei operacje na obiektach to zazwyczaj standardowy CRUD. Wiążąc te dwa fakty można użyć standardowych metod HTTP do wykonania standardowych akcji na obiektach:

  • POST - tworzenie obiektów (Create)
  • GET - pobieranie danych (Read)
  • PUT - tworzenie/aktualizacja obiektów (Create/Update)
  • DELETE - usuwanie obiektów (Delete)

przykładowe wywołania:
  • http://web-services.pl/klient za pomocą metody POST - zostanie utworzony nowy klient (identyfikator zostanie nadany przez operację)
  • http://web-services.pl/klient/34 za pomocą metody GET - zostaną zwrócone dane klienta o podanym identyfikatorze
  • http://web-services.pl/klient/34 za pomocą metody PUT - dane klienta zostaną zaktualizowane
  • http://web-services.pl/klient/34 za pomocą metody DELETE - klient o podanym identyfikatorze zostanie usunięty

Ważne jest to, żeby w URI posługiwać się rzeczownikami. To tak samo jak w rzeczywistym świecie - mamy np. stół, a na nim szklankę, ołówek, notes, dziurkacz. Każdą z tych rzeczy możemy wziąć (ang. GET). wziąć (GET) szklankę, wziąć (GET) ołówek, wziąć (GET) notes itd...
Ten sam czasownik (GET) stosowany do RÓŻNYCH przedmiotów (rzeczowniki). Proste, nie? Niektóre czasowniki można stosować jednak tylko do wybranych rzeczowników - nie można np. pisać notesem, albo pić z ołówka :)

jak może wyglądać przykładowa odpowiedź na pytanie http://web-services.pl/klieci (GET):

<?xml version="1.0"?>
<p:Part xmlns:p="http://www.parts-depot.com"
xmlns:xlink="http://www.w3.org/1999/xlink">
<klienci>
<klient id="34" xlink:href="http://web-services.pl/klient/34"/>
<klient id="35" xlink:href="http://web-services.pl/klient/35"/>
<klient id="36" xlink:href="http://web-services.pl/klient/36"/>
</klienci>
</p:Part>

Nie jesteśmy jednak ograniczeni do używania XMLa - możemy produkować inny rodzaj na wyjściu. W ogóle nie musimy używać XMLa, możemy użyć np.: JSONa, ATOMa, YAMLa... Poniżej kod prostego serwisu - pozostawiam bez komentarza, ponieważ jest dość intuicyjny:

@Path("/klient/{id}")
public class UserResource {

@GET @Produces("application/xml"})
public User getKlient(@PathParam("id") String id) {
return lookupCustomer(id);
}

@PUT @Consumes("application/xml"})
public void putUser(@PathParam("id") String id, Customer u) {
return updateCustomer(id, u);
}

}