Przeglądając ostatnio dokumentację API serwisu Blip natrafiłem na stwierdzenie, iż architektura intefejsu programistycznego Blip.pl wykonana jest zgodnie ze wskazaniami stylu REST. Generalnie wiedziałem o co chodzi; czytelnie skonstruowane odnośniki reprezentują zasoby serwisu a do manipulowania nimi stosuje się metody protokołu HTTP (GET – pobranie zasobu, POST – utworzenie itp.)
Również niedawno Mateusz wrócił z JDD i Cooluarów, które odbywały się w Krakowie. Zdał mi relację z ciekawej prezentacji dotyczącej RESTful Web Services. Wydały mi się ciekawą i “lekką” alternatywą dla usług sieciowych opartych o protokoły SOAP i WSDL. W tym wpisie zamieszczam moje rozpoznanie tematu.
Zacznijmy od nazwy. Termin REST określa styl architektury typu klient-serwer, w której komunikacja polega na przesyłaniu reprezentacji zasobów – wolne tłumaczenie definicji z Wikipedii. Zasobem może być każdy sensowny „obiekt” (lub „byt”), do którego można się jakoś odnieść a reprezentacja to dokument przedstawiający faktyczny lub pożądany stan tego obiektu.
Przykład
Zasobem może być np. model samochodu a pod adresem http://samochody.info/peugeot/106 znajdować się może dokument w formacie HTML, który opisuje go w jakiś sposób. Dokument ten może zawierać odnośnik http://samochody.info/peugeot/106/zdjecie.jpg, który jest reprezentacją zdjęcia tego modelu samochodu. Z kolei odwiedzając http://samochody.info/peugeot otrzymamy listę wszystkich modeli wraz z odnośnikami.
Styl REST został początkowo opisany w kontekście protokołu HTTP; istnieje w nim wiele sposobów reprezentacji zasobów (URL, URI, typy MIME) oraz metod manipulacji nimi (GET, POST, PUT, DELETE).
RESTful Web Services są usługami sieciowymi opartymi o protokół HTTP i zasady stylu REST. Zazwyczaj metody protokołu odpowiadają typowym operacjom CRUD:
- POST – CREATE
- GET – READ
- PUT – UPDATE
- DELETE – DELETE
JSR-311 to formalny dokument opisujący API do tworzenia usług sieciowych w stylu REST z użyciem języka i platformy Java (Java API for RESTful Web Services – JAX-RS). Wersja 1.0 specyfikacji została wydana 8 września 2008 roku. To nowoczesne API, korzysta ze wszelkich dobrodziejstw Javy – adnotacji, wstrzykiwania zależności.
Usługa sieciowa stworzona z użyciem JAX-RS składa się (głównie) z dwóch rodzajów klas:
- klas zasobów,
- klas dostawców.
Klasy zasobów implementują zasoby i operacje z nimi związane, są to zwykłe POJO a wszelkie sprawy związane z protokołem HTTP załatwiamy adnotacjami:
| Adnotacja | Opis |
|---|---|
@GET, @POST itd. |
Określa, które metody klasy odpowiadają poszczególnym metodom HTTP. |
@Path |
Pozwala na zdefiniowanie szablonu URI używanego przez usługę sieciową. |
@Produces, @Consumes |
Przypisuje typ MIME reprezentacji, które jest tworzona lub przetwarzana przez metodę klasy. |
@QueryParam, @PathParam, @CookieParam, @HeaderParam |
Określa, skąd brane są wartości parametrów przekazywanych do metod klasy. |
Klasy dostawców zgodnie z nazwą dostarczają różne usługi. Podzieleni są na trzy grupy:
| Grupa | Opis |
|---|---|
| Dostawcy encji | Zajmuję się mapowaniem obiektów Javy na reprezentację oraz na odwrót. Implementują interfejsy MessageBodyReader i/lub MessageBodyWriter. |
| Dostawcy kontekstu | Dostarczają kontekst klasom zasobów i innym dostawcom. Implementują interfejs ContextResolver<T>, gdzie T jest typem kontekstu. |
| Dostawcy mapowania wyjątków | Mapują wyjątki rzucane przez inne klasy na odpowiedź HTTP. Implementują interfejs ExceptionMapper<T> |
Przykład
@Path("/") public class CarResource { @GET @Path("/{make}/{model}/") @Produces("application/xml") public CarModel getModel(@PathParam("make") String make, @PathParam("model") String model) { // ... } @POST @Path("/") @Consumes("application/json") public Response addModel(CarModel model) { // ... } }
Powyższy kod przedstawia prostą klasę służącą do implementacji zasobu reprezentującego modele samochodów. Zasób ten jest dostępny na głównej ścieżce URI (@Path("/"), np. http://samochody.info/).
Użycie metody GET zwróci nam opis modelu samochodu w formacie XML (@GET, @Produces("application/xml")). URI, który należy podać klientowi to np. http://samochody.info/peugeot/106/ (@Path("/{model}/{make}/")). Metoda getModel przyjmuje dwa parametry typu String, które są pobierane z URI (@PathParam("model") i @PathParam("make") – odpowiadają one fragmentom {model} i {make} z adnotacji @Path). Druga metoda tworzy nowy zasób. Dane są przekazywane metodą POST w formacie JSON.
Przykłady z użyciem Apache CXF
CXF jest frameworkiem służącym do tworzenia wszelkiego rodzaju usług. Wspiera wiele różnych protokołów oraz standardów: SOAP, WSDL, WS-Security, JAX-WS oraz właśnie JAX-RS. Usługi stworzone z jego pomocą możemy używać w różnych kontenerach; od Tomcata i Springa po serwery aplikacyjne zgodne z całą specyfikacją Java EE. CXF zresztą wchodzi w skład serwera Apache Geronimo.
Poniższe przykłady są do ściągnięcia w postaci spakowanych projektów mavenowych. Kompilemy je wydając polecenie mvn compile a uruchamiamy poprzez mvn exec:java.
Car Service
Pierwszy przykład to prosta usługa do przechowywania informacji o modelach samochodów (która była wspominana wcześniej). Przy uruchomieniu zawiera tylko model Peugeota 106, dostępny pod adresem http://localhost:9000/peugeot/106/ (wystarczy skorzystać z przeglądarki).
Żeby dodać jakiś model samochodu, musimy wysłać do usługi jego reprezentację w formacie JSON metodą POST protokołu HTTP. Możemy to zrobić przy użyciu programu curl:
curl -v -H "Content-Type: application/json" -d {"car-model":{"make":"Renault","model":"Clio"}} \ http://localhost:9000/
Todo Service
Tak jak pierwszym programem napisanym w trakcie nauki języka programowanie jest Hello World (albo Hello, I am JanB), tak dla frameworków webowych zaczyna przyjmować się zwyczaj, że pierwszym programem jest lista zadań (śmiem twierdzić, że mój kolega jest autorem tego zwyczaju). Zgodnie z tą tradycją zachęcam do testowania usługi sieciowej RESTful – Todo Service.
Wszystkie zadania:
curl http://localhost:9000/todo/
Nowe zadanie:
curl -v -H "Content-Type: application/xml" -d "<task><description>Nowe zadanie</description></task>" \ http://localhost:9000/todo/
Uaktualnienie zadania:
curl -v -H "Content-Type: application/xml" \ -X PUT -d "<task><id>2</id><description>Nowe zadanie</description><done>true</done></task>" \ http://localhost:9000/todo/
Usunięcie zadania:
curl -v -X DELETE http://localhost:9000/todo/1/
Comments
Leave a comment Trackback