%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% :REST %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%t \section{RESTful webové služby} \label{RESTful Web Services} REST (Representational State Transfer) je odlišný koncept webové služby od dříve vzniklého RPC. Staví na protokolu HTTP. Podle RESTful webových služeb se web skládá z~jednotlivých zdrojů (resources -- z~kapitoly \ref{HTTP}). Každý zdroj má v~určitou chvíli nějaký stav (pozor, neplést s~bezestavovostí HTTP -- ta zakazuje stav komunikaci mezi klientem a~serverem, nikoli stav zdroje). Klient pak na požádání může stav zdroje získat jako tzv. reprezentaci. Idea RESTful webových služeb je co nejvíce využít stávající protokol HTTP namísto vymýšlení nových návrhů. \subsection{Webové zdroje} Webový zdroj je abstraktní prvek, který by se dal přirovnat k~objektu v~objektově orientovaném programování -- v~danou chvíli má určitý stav, reaguje na vybrané metody, a~má nějakou adresu (v~případě objektu adresu v~paměti, v~případě RESTu adresu URI). Tak, jako se v~objektově orientovaném programování říká, že všechno je objekt, pak pro REST platí, že vše je zdroj. Domovská stránka internetového vyhledávače je zdroj, samotný vyhledávací algoritmus je zdroj, PDF dokument uložený na serveru a~zpřístupněný na internetu je zdroj, obrázek je zdroj, spustitelný soubor je také zdroj. Vždy víme jaké reprezentace zdroj nabízí a~na jaké metody dokáže reagovat. \begin{figure}[ht] \centerline{\includegraphics[height=80mm]{images/800px-Brown_bear_(Ursus_arctos_arctos)_running.jpg}} \caption{Obrázek je v~RESTu také webový zdroj (obrázek: Wikipedia).} \end{figure} \subsection{Adresovatelnost} Každý zdroj musí mít svoji unikátní adresu URI. Výhodou tohoto návrhu je, že se na jednotlivé zdroje můžeme přímo odkazovat. RESTful webové služby používají výhradně protokol HTTP, proto zde pod pojmem URI myslíme jeho zúženou variantu -- URL. Připomeňme si, že adresa zdroje seskládá z~protokolu (tedy \emph{http:\/\/}) následovaného adresou serveru (např. \emph{www.myexample.com}), dále cestou ke zdroji (např. \emph{/dictionary/search}) a~případným HTTP query (např. \emph{?keyword=pine}). Jelikož adresa serveru je zpravidla pevně daná při nasazení aplikace, zaměříme svou pozornost hlavně na cestu a~později také na část query. \subsection{Hierarchie zdrojů} Zdroje webové aplikace tvoří v~RESTu stromovou hierarchii podle svých adres. RESTful webová služba je většinou nasazena na jednom serveru, všechny adresy mají tedy společný protokol a~server. Pro jednoduchost budeme tedy dále pracovat pouze s~hierarchií cest ke zdrojům. V~kořeni je uložena kontextová cesta identifikující webovou službu (viz. kapitola \ref{Deployement}). V~našem případě server \emph{www.animalia.com} hostuje pouze jednu webovou službu a~cestu k~ní má nastavenou jako \emph{/}. Pro každý webový zdroj v~aplikaci máme právě jeden uzel ve stromu. Uzel ve stromu \emph{B} je potomkem uzlu \emph{A} právě když webový zdroj \emph{B} je součástí webového zdroje \emph{A}. Fráze ``je součástí'' je proměnlivá. Někdy může jít o~specializaci třídy jako v~objektově orientovaném programování, jindy se lépe hodí vztah ``B patří do A'' (kolekce), nebo dokonce ``A má/používá B''. Vše závisí na konkrétním problému, který aplikace řeší. \subsection{Návrh Hierarchie} Návrh hierarchie webových zdrojů je pro aplikaci klíčová věc. Přitom není vůbec jednoduché vymyslet dobré řešení. Ukážeme si návrh stromu pro aplikaci Animalia spolu s~postupnými úvahami k~jednotlivým prvkům hierarchie. Začněme se~samotnou aplikací. Ta bude mít finální cestu \emph{/}. Aplikace má za úkol podávat informace o~zvířatech. Prozatím plánujeme dodat pouze savce, z~hlediska budoucnosti ale uvažujeme i~o~ptácích a~rybách. Vytvoříme tedy uzel \emph{savci} a~přidáme ho jako potomka kořeni. Situaci ilustruje obrázek \ref{Building REST tree 1} \begin{figure}[ht] \centerline{\includegraphics[height=40mm]{images/rest_tree_2.png}} \caption{Strom s uzlem \emph{savci}.} \label{Building REST tree 1} \end{figure} Uzel \emph{savci} bude reprezentovat seznam všech savců v~Animalii. Pro další postup máme dvě možnosti. První je začít přidávat další prvky taxonomického systému. Uzel s~názvem \emph{šelmy} (z~hlediska taxonomie jde o~řád) by reprezentoval seznam všech šelem a~byl by potomek uzlu \emph{savci}. Na stejné úrovni jako on by pak byly i~uzly \emph{primáti}, \texttt{sudokopytníci} a~další (všechno jsou to řády). Pod řády by následovaly čeledi a~pod nimi už samotná zvířata. Tento návrh se zpočátku jeví jako systematický, brzy bychom ale přišli na to, že strom velmi narůstá a~vše se zbytečně komplikuje. Prakticky by odpadla možnost, aby si lidský uživatel pamatoval výslednou adresu k~nějakému zvířeti. Snazší je tedy jednotlivé savce napojit jako přímé potomky uzlu \emph{savci}. Obrázek \ref{Building REST tree 2} ukazuje srovnání původního návrhu s~novým. \begin{figure}[ht] \centerline{\includegraphics[height=100mm]{images/rest_tree_3c.png}} \caption{Srovnání dvou návrhů.} \label{Building REST tree 2} \end{figure} Při návrhu je potřeba si uvědomit že neexistuje jediné správné řešení. Některá řešení nabídnou lepší škálovatelnost aplikace, jiná zase praktické adresy. Celému návrhu je však potřeba věnovat zvýšenou pozornost. Tím spíše. že jednou zveřejněné adresy webových zdrojů se dají jen velmi obtížně vzít zpátky. Je tedy lepší vše důkladně promyslet a~třeba i~zkusit návrhů více a~u~každého zvážit jaký bude mít na aplikaci vliv. \newpage \subsection{Sestavení adresy zdroje} Ze stromu hierarchie sestavíme adresu URI pro cílový webový zdroj následovně. Jako první část adresy položíme \emph{http://}. Za ni připojíme adresu serveru, v~našem případě \emph{www.animalia.com}. Následně jdeme od kořene cestou k~požadovanému uzlu a~přes každý uzel přes který projdeme připojíme na konec již sestavené adresy jeho název následovaný lomítkem. Poslední lomítko (tedy to za názvem koncového uzlu) můžeme vypustit. Tím získáme celou adresu URI pro daný webový zdroj. Příklad ukazuje, jak postupně sestavit adresu zdroje \emph{medvěd hnědý} z~návrhu stromu zdrojů (viz. obrázek \ref{Building REST tree 2} vpravo). \begin{Verbatim} http:// http://www.animalia.com http://www.animalia.com/ http://www.animalia.com/savci/ http://www.animalia.com/savci/medvěd_hnědý/ \end{Verbatim} \subsection{Výhody hierarchie zdrojů} Hierarchie webových zdrojů vnáší do aplikace systematičnost a~přehlednost. Kromě toho můžeme použít podobný webový zdroj na dvou různých místech hierarchie. V~publikaci \cite{RESTful Web Services} například navrhují aplikaci zpracovávající mapy. Aplikace je podobná již existujícím Google Maps. Autoři používají mapy geografické i~dopravní. Hierarchie adres umožňuje do aplikace snadno zařadit jak geografickou mapu města Olomouc tak dopravní mapu Olomouce. Adresy \emph{/maps/geographical/Czech\_Republic/Olomouc} a~\emph{/maps/traffic/Czech\_Republic/Olomouc} jsou navzájem rozdílné a~přestože webový zdroj na konci každé z~nich se jmenuje \emph{Olomouc}, reprezentuje jinou mapu Olomouce (z~kontextu celé cesty). Zároveň si však uchovává intuitivní a~jednoduché jméno. \subsection{Reprezentace} Webové zdroje jsou pouze abstraktní část RESTful webové služby. Na požádání můžeme dostat jejich reprezentaci. Na rozdíl od SOAPu, v~RESTu může být reprezentace jakýkoliv formát na kterém se poskytovatel služby a~její klient dohodnou. Mezi oblíbené formáty patří XML, HTML a~podle \cite{RESTful Web Services} také XHTML a~JSON. Neznamená to však, že je nutné implementovat všechny tyto reprezentace. Často stačí jedna pro lidského uživatele (např. HTML) a~druhá pro programové zpracování (např. XML). Klient webové služby si pak požadovanou reprezentaci určí v~HTTP položce hlavičky \texttt{Accept}. Při návrhu své RESTful webové služby je pak třeba mít na paměti, že slouží dohromady lidským uživatelům i~počítačům. \subsection{Metody zdrojů} Koncept RESTu vychází z~námitky: proč zavádět nové metody (jako v~RPC) když protokol HTTP sám o~sobě již kvalitně navržené metody poskytuje. REST kromě metod \texttt{GET} a~\texttt{POST} resuscitoval metody \texttt{HEAD}, \texttt{PUT} a~\texttt{DELETE}. Každý webový zdroj pak umí reagovat na nějaké tyto metody. Co bude konkrétně výsledkem například metody \texttt{GET} je na webové službě, musíme se ovšem řídit obecnými zásadami, které si teď popíšeme. \subsubsection{GET} Metoda \texttt{GET} byla popsána v~kapitole \ref{HTTP} a~řídí se stejnými pravidly. V~RESTful webové službě by měly všechny webové zdroje umět reagovat ne metodu \texttt{GET}. Odpovědí na tuto metodu je vrácení reprezentace požadovaného zdroje. Pokud si u~některého zdroje nejsme jistí, jak by měla taková reprezentace vypadat (nastává obzvláště u~zdrojů zavedených pouze kvůli hierarchii adres, např. zdroj reprezentující celou aplikaci), osvědčilo se vrátit alespoň stručný HTML popis pro lidského uživatele spolu s~odkazy na další funkce aplikace. \subsubsection{HEAD} Metoda \texttt{HEAD} značí, že se ptáme pouze na existenci daného webového zdroje. Reakcí na ni je vrátit \texttt{200 OK} bez přiložené reprezentace pokud zdroj existuje, \texttt{404 Not Found} pokud neexistuje. Metoda \texttt{HEAD} najde využití především u~aplikací obsahující potenciálně nekonečně různých zdrojů (např. záznamy ve slovníku). V~publikaci \cite{RESTful Web Services} se doporučuje, aby každý zdroj uměl na metodu \texttt{HEAD} reagovat. Pokud by ale měly vaše zdroje vracet konstantní odpověď \texttt{200 OK}, je tento požadavek poněkud zbytečný a~dá se s~klidem opomenout. Příklad ukazuje syntaxi metody. Ptáme se webové aplikace Animalia zda-li obsahuje záznam o~medvědu hnědém (\emph{ursus arctos}. Zajímá nás pouze odpověď \texttt{true} / \texttt{false}). \begin{Verbatim} HEAD /search/ursus+arctos HTTP/1.1 Host: www.animalia.com \end{Verbatim} \subsubsection{PUT} Metoda \texttt{PUT} je určená pro vytváření a~měnění webových zdrojů. Zdroj vytvoříme tak, že pošleme požadavek \texttt{PUT} na danou adresu (v~tomto případě na adresu doposud neexistujícího zdroje). V~příloze pošleme reprezentaci zdroje. Webová služba pak na této adrese vytvoří nový zdroj s~reprezentací, kterou si vyzvedne z~těla požadavku. Pokud už na dané adrese zdroj byl, přepíše se novými daty. Metoda \texttt{PUT} tedy funguje jako nastavovací (\emph{set}) metoda v~jazyce Java. Často je používána ve spojení s~autorizací. Následující příklad ukazuje, jak v~aplikaci Animalia vytvořit záznam o~vlkovi obecném (\emph{canis lupus}). Reprezentace dat v~příloze byla zjednodušena. \begin{Verbatim} PUT /savci/canis/lupus HTTP/1.1 Host: www.animalia.com Content-Type: application/xml Content-Length: 108 LC \end{Verbatim} Je potřeba mít na paměti, že pohled RESTu na celou aplikaci je poněkud odlišný než jak jsme zvyklí z~běžného programování. Podle RESTu má každý zdroj svou vlastní adresu (a~naopak). I~neexistující webový zdroj je tedy naprosto regulérní a~umí reagovat například na metody \texttt{GET} a~\texttt{HEAD} (vrací \texttt{404 Not Found}). Pokud tedy webová služba na požadované adrese neumožňuje vytvořit nový zdroj, vrací odpověď \texttt{405 Method Not Allowed} (zdroj virtuálně existuje ale nemá povolenu metodu \texttt{PUT}). \subsubsection{DELETE} Metoda \texttt{DELETE} je určená pro mazaní webových zdrojů. Reakcí webové služby na \texttt{DELETE} požadavek je smazání celého webového zdroje na dané adrese (včetně všech jeho reprezentací). Tento proces je nevratný a~bývá často spojen s~autorizací. Interpretace smazání je na autorovi webové služby, běžné však bývá, že pokud pošleme \texttt{DELETE} na nějaký zdroj, smažou se tím i~všechny zdroje v~jeho podstromu hierarchie (např. smažeme všechny savce v~Animalii). Obecně se nedoporučuje aby každý zdroj webové služby uměl reagovat na \texttt{DELETE} (tedy byl smazatelný). Příklad ukazuje požadavek na smazání záznamu o~medvědovi hnědém (\emph{ursus arctos}). \begin{Verbatim} DELETE /savci/canis/lupus HTTP/1.1 Host: www.animalia.com \end{Verbatim} \subsubsection{POST} Metoda \texttt{POST} slouží k~zasílání dat na server a~k~vytváření webových zdrojů. Byla popsána v~kapitole \ref{HTTP} Na rozdíl od metody \texttt{PUT} nemusíme znát finální adresu vytvářeného zdroje. Namísto toho bývá ve webové službě vytvořen webový zdroj nazývaný koncový bod, který přijímá \texttt{POST} požadavky a~zpracovává je. Webová služba si pak sama určí výslednou adresu a~webový zdroj zde vytvoří. Toto pro uživatele zdánlivě pohodlnější řešení je ovšem vyváženo vážnou nevýhodou. Vzniká problém poznat kdy chceme aktualizovat stará data a~kdy vytvořit nová. Obecně se tedy v~RESTful webových službách příliš nedoporučuje metodu \texttt{POST} používat. \subsection{Reakce na metody} Reakce na jednotlivé metody jsou vyjádřeny kódem HTTP odpovědi. Umět vybrat správný kód jako reakci na nějakou metodu je z~hlediska návrhu služby velmi důležité a~často se to dá nazvat uměním. V~následujících odstavcích si podrobněji popíšeme některé často používané kódy. Seznam všech kódu spolu s~diskuzí, kdy které používat je možné najít v~\cite{RESTful Web Services}. \subsubsection{200 OK} Toto je asi nejčastěji používaný kód. Slouží jako reakce na metodu \texttt{GET}, kdy v~těle odpovědi následuje přiložena reprezentace webového zdroje. Reakce na metodu \texttt{HEAD} zase znamená, že zdroj existuje. Kód \texttt{200 OK} se běžně také používá jako kladná reakce na \texttt{PUT} (zdroj byl vytvořen) a~na \texttt{DELETE} (zdroj byl smazán). \subsubsection{201 Created} Tento kód je téměř výhradně reakcí na \texttt{POST} metodu. V~poli hlavičky \texttt{Location} je adresa nově vytvořeného webového zdroje. \subsubsection{202 Accepted} Tento kód se používá pro asynchronní operace (uvedené později). \subsubsection{204 No Content} Kód \texttt{204 No Content} je podobný jako kód \texttt{200 OK}, tedy kladné vyřízení požadavku. Název \emph{No Content} značí, že odpověď nemá přiložena žádná data. Někteří návrháři webových služeb ho používají jako kladnou reakci na metodu \texttt{HEAD}, zatímco jiní používají výhradně \texttt{200 OK}. \subsubsection{206 Partial Content} Tento kód se používá pro částečný GET (uveden později). \subsubsection{301 Moved Permanently} Tento kód slouží pro přesměrování tak, jak bylo popsáno v~kapitole \ref{HTTP} Pokud je přesměrování reakcí na metody \texttt{PUT}, \texttt{POST} nebo \texttt{DELETE}, operace nebude provedena a~uživatele musí poslat celý požadavek znovu na novou adresu. U~RESTful webových aplikací je potřeba dát si pozor na nekonečné smyčky přesměrování. \subsubsection{303 See Other} Kód \texttt{303 See Other} se používá, pokud daná adresa slouží pouze jako alias. Reakce na metodu \texttt{GET} má stejný výsledek jako přesměrování, pouze důvod je jiný. Zdroj se nepřestěhoval ale jeho skutečná adresa je jiná. Někteří vývojáři preferují vracet reprezentaci takovéto zdroje přímo a~nepožadovat po uživateli nový \texttt{GET} požadavek na jinou adresu. Reakce na metody \texttt{PUT}, \texttt{POST} a~\texttt{DELETE} znamená, že operace byla provedena (na rozdíl od \texttt{301 Moved Permanently}). Její výsledek (pokud je zobrazitelný) si můžeme prohlédnout na nové adrese. \subsubsection{304 Not Modified} Tento kód se používá pro podmíněný GET (uveden později). Tato odpověď znamená, že požadovaný zdroj nebyl měněn. Je s~podivem, že tento kód patří do řady 3xx (nazývané \emph{přesměrovaní}), přesto že v~něm očividně o~žádné přesměrování nejde. \subsubsection{307 Temporary Redirect} Je podobný jako kód \texttt{304 Moved Permanently} pouze s~tím rozdílem, že autor webové aplikace očekává, že se zdroj po nějaké době vrátí opět na starou adresu. Toto nastává nejčastěji při údržbě serveru kde je aplikace dočasně hostována v~provizorních podmínkách jinde. \subsubsection{400 Bad Request} Kód \texttt{400 Bad Request} je nejvíce obecnou výjimkou, že v~požadavku je chyba. často se používá jako reakce na \texttt{PUT} a~\texttt{POST} pokud přiložená data nedávají smysl (například chybí adresa pro dodání objednávky). Na metody \texttt{GET} a~\texttt{HEAD} se jako reakce nepoužívá. Na \texttt{DELETE} pouze ve vzácných případech, kdy zdroj potenciálně lze smazat ale zrovna teď ne (u~relační databáze by to mohlo být třeba kvůli cizím klíčům). \subsubsection{401 Unauthorized} Toto je velmi běžný kód související s~autorizačním procesem, který byl popsán v~kapitole \ref{HTTP} \subsubsection{403 Forbidden} Tento kód je serverem poslán tehdy, když je požadovaný zdroj v~chráněné oblasti, ale přístupu k~němu nelze dosáhnout ani znalostí uživatelského jména či hesla. Často se používá v~případě konfiguračních souborů nebo souborů s~uloženými hesly. Dalším použitím je dočasné odstavení webové služby v~rámci správy serveru. \subsubsection{404 Not Found} Tento kód bývá nejčastěji zasílán jako reakce na \texttt{GET} pokud se požadovaný webový zdroj v~aplikaci nevyskytuje a~to buď z~důvodu chyby v~adrese (uživatel se spletl), nebo zcela regulérně (slovíčko ve slovníku není ap.). \subsubsection{405 Method Not Allowed} Tento kód se vrátí pokaždé když pošleme na webový zdroj požadavek s~metodou, na kterou daný zdroj neumí zareagovat. V~praxi je to například na požadavek \texttt{DELETE}, který pro tento zdroj není povolen (tedy zdroj nelze smazat). \subsubsection{409 Conflict} Kód \texttt{409 Conflict} značí, že zaslaný požadavek byl chybný a~byl odmítnut. Jedná se zpravidla o~reakci na metody \texttt{PUT}, \texttt{POST} která vyjadřuje, že požadavek by uvedl webový zdroj do nekonsistentního stavu. Je to například tehdy, když měníme metodou \texttt{PUT} již existující data a~některou důležitou položku (uživatelské jméno, identifikační číslo ap.) bychom se snažili nastavit na nepovolenou hodnotu (např. na již existující identifikační číslo). Eventuelně by mohlo jít i~o~reakci na \texttt{DELETE}, nikdy však ne na \texttt{GET} nebo \texttt{HEAD}. \subsubsection{410 Gone} Tento kód je prakticky stejný jako kód \texttt{404} pouze s~rozdílem, že v~případě \texttt{410 Gone} si server pamatuje, že na požadované adrese se webový zdroj nalézal ale už zde není (byl smazán). Tato reakce je povolena pro všechny metody kromě \texttt{DELETE}. U~té by totiž nebylo jasné, jestli jsme webový zdroj právě smazali, nebo už byl odstraněn předtím. \subsubsection{415 Unsupported Media Type} Tímto kódem nám server oznamuje, že data přiložená v~těle \texttt{PUT} nebo \texttt{POST} požadavku neumí zpracovat. Stává se to tehdy, když na server přijímá reprezentace webových zdrojů například pouze ve formátu XML a~my je pošleme ve formátu JSON. Pokud bychom poslali data v~XML, které by ovšem bylo špatně formátované nebo neobsahovalo všechny potřebné údaje, vrátila by se nám odpověď \texttt{400 Bad Request}. \subsubsection{500 Internal Server Error} Kód \texttt{500 Internal Server Error} značí, že na serveru došlo k~chybě a~požadavek nemohl být zpracován. Tento kód návrhář webové služby nikdy neplánuje, jelikož se jedná o~neočekávanou výjimku na straně serveru. U~některých aplikací se můžeme setkat s~tím, že kód \texttt{500 Internal Server Error} vrací jako odpověď na špatně strukturovaný požadavek (např. WSServlet pro SOAP webové služby jej vrací na všechny špatné SOAP požadavky). Tento přístup je však nevhodný. Pro špatný požadavek slouží kód \texttt{400 Bad Request}. \subsubsection{503 Service Unavailable} Tento kód je zaslán pokud webová služba dočasně není přístupná, například z~důvodu údržby. Takováto odpověď může obsahovat pole hlavičky \texttt{Retry-After} spolu s~odhadem, kdy bude znovu zprovozněna. \subsection{Transparentnost} V~RESTu je důležité, že všechny zdroje jsou z~hlediska klienta transparentní. Nikdy nevíme, jak je zdroj na serveru implementován. Například u~HTML stránky nevíme, jestli jde o~soubor uložený na disku, nebo jestli se tato stránka vyrobí až za běhu aplikace. To je, podobně jako v~objektově orientovaném programování, důležité kvůli snadno předělatelnému kódu. Podívejte se nyní na obrázek \ref{REST_XML} \begin{figure}[ht] \centerline{\includegraphics[height=70mm]{images/rest_xml_xml.png}} \caption{Skladování dat v~XML} \label{REST_XML} \end{figure} Zde aplikace v~reakci na \texttt{GET} požadavek čte soubor \emph{vulpes\_vulpes.xml (1)} a~data z~něj přečtená sestaví do objektu \texttt{Animal}. Tento objekt je pak za pomocí objektu \texttt{AnimalXmlSerializer} sestaven zpět do XML souboru (2), který je následně odeslán v~odpovědi. Přitom soubory (1) a~(2) nemusí být vůbec stejné. Odesílaný soubor může být klidně obohacen o~obrázky, nebo může obsahovat lokalizovaný text. Hlavní výhoda tohoto zdánlivě překomplikovaného návrhu ale přijde v~době, kdy se rozhodneme vyměnit způsob uložení dat v~XML souborech za databázi, jak ukazuje obrázek \ref{REST_DB} \newpage \begin{figure}[ht] \centerline{\includegraphics[height=70mm]{images/rest_db_xml.png}} \caption{Skladování dat v~databázi} \label{REST_DB} \end{figure} Všimněte si, že největší změna, která nás čeká je přesunutí dat do databáze a~posléze implementování třídy \texttt{AnimalSQLDbLoader}, která se bude hlásit k~rozhraní \texttt{AnimalLoader}. Poslední detail bude, že instanci třídy \texttt{AnimalIO} přesměrujeme na nový nahrávací systém. Toto je jednoduchá implementace návrhového vzoru Most (\emph{Bridge}, k~dispozici v~\cite{Navrhove vzory}. Nejdůležitější ale je, že adresy ani nabízené reprezentace našich zdrojů se nezměnily. Pořád můžeme požadovat zdroj \emph{vulpes.xml} i~přesto, že na serveru už žádné XML soubory nenajdeme. Ty se teď sestaví za běhu z~dat načtených z~databáze. \subsection{Alternativní volba reprezentace} Pokud při návrhu webové služby předpokládáte, že její lidští uživatelé budou používat převážně webový prohlížeč, nemusí být od věci zavést alternativní možnost pro vybrání formátu reprezentace. Málokterý prohlížeč umožňuje uživateli zasahovat do formátu HTTP požadavků které posílá. Pokud například nějaký zdroj nabízí svou reprezentaci jak v~HTML, tak v~PDF, pak je by uživatel formát PDF nemohl nikdy získat (prohlížeč preferuje MIME typ \emph{text/html}). V~takovémto případě se nabízí alternativní možnost vybrání formátu reprezentace pomocí tečkové notace, která připomíná typ souboru. \begin{Verbatim} /savci/medved_hnedy.html /savci/medved_hnedy.pdf \end{Verbatim} Toto jsou dvě reprezentace téhož zdroje. Ta první je ve formátu HTML, zatímco druhá je v~PDF. Předpokládáme, že obě tyto reprezentace obsahují stejná data (stejný článek o~medvědovi hnědém), pouze v~jiném formátu. Všimněte si, že tento přístup jenom rozšiřuje princip, že cesty ke zdrojům vypadají jako cesty k~souborům na osobním počítači. Přitom je zachována transparentnost -- nevíme, jestli na serveru existuje soubor \emph{vulpes.pdf}, nebo jestli je tento dokument dynamicky sestaven za běhu aplikace. \subsection{Volba jazyka reprezentace ve vícejazyčné aplikaci} Výběr formátu reprezentace už znáte. Pokud chcete vyvíjet vícejazyčnou webovou aplikaci, bude vás zajímat, jak se bude dát vybrat požadovaný jazyk. Z~teoretického hlediska je situace podobná jako při výběru formátu, z~praktického ale znatelně obtížnější. V~HTTP existuje pro tento účel položka hlavičky zvaná \texttt{Accept-Language}. Umožnit však výběr pouze přes ni se však příliš nedoporučuje. Pokud bude mít uživatel například anglickou verzi operačního systému (u~Linuxu jde o~naprosto běžnou věc), pak bude jeho prohlížeč preferovat angličtinu a~k~českým materiálům se nedostane. Řešením je opět zkusit zavést tečkovou notaci. Představte si, že naše encyklopedie bude dostupná ve více jazycích -- konkrétně češtině, angličtině, švédštině a~norštině. Pak zdroj \emph{liska\_polarni} může nabízet následující reprezentace. \begin{Verbatim} /savci/liska_polarni.cz /savci/liska_polarni.en /savci/liska_polarni.se /savci/liska_polarni.no \end{Verbatim} Pokud jste ve službě už použili tečkovou notaci pro výběr formátu reprezentace a~adresy jako \emph{/animalia/savci/liska\_polarni.html.cz} se vám nelíbí, je možné výběr jazyka zakombinovat do jiné části adresy. Pokud vám to povaha aplikace a~server dovolí, pak můžete výběr jazyka zapracovat do adresy serveru tak, jako to má encyklopedie Wikipedia -- \emph{http://en.wikipedia.org} (pozn. Wikipedie není RESTful webová služba). V~opačném případě můžete použít některou část cesty, například \emph{http://www.animalia.com/cz/savci}. Použití výběru jazyka v~části query není vhodné. \subsection{Kontroverze tečkové notace} Přestože zmíněná tečková notace je jak v~případě výběru formátu, tak ve výběru jazyka velmi doporučována v~\cite{RESTful Web Services}, není úplně bez vad. Jakýmsi nepříjemným způsobem se stává součástí adresy zdroje. Představte si, že do zmíněné encyklopedie bude možno nahrávat články pomocí požadavku s~metodou \texttt{PUT}. Aplikace bude umět parsovat pouze přiložená data ve formátu XML s~předem definovanou gramatikou. Můžeme takovýto požadavek poslat na adresu \emph{http://www.animalia.com/savci/liska\_polarni\textbf{.html}}? I~smazání zdroje přestává být intuitivní. V~někom by to mohlo vzbudit dojem, že smažeme pouze HTML reprezentaci. Pravdou však je, že smazat můžeme pouze celý zdroj. Z~těchto a~dalších důvodů se jedná o~kontroverzní řešení a~vždy bychom měli zvážit, jestli nám stojí za to. Jednoduchost a~intuitivnost patří přece mezi hlavní výhody RESTful služeb. \subsection{Propojitelnost} Další zásadou v~RESTu je propojitelnost webových zdrojů. To znamená, že zdroje, které spolu souvisí, nebo jsou jeden součástí druhého, na sebe obsahují odkaz. Ten může být realizován jako \texttt{a} element v~jazyce HTML, XLink v~jazyce XML (více informací o~XLink v~\cite{Xlink Wikipedia} nebo v~\cite{XML v kostce}), nebo jiný. Hlavní myšlenkou propojitelnosti je, že často nepotřebujeme okamžitě získat vše, co webová služba nabízí. Pokud žádáme o~všechny savce (zdroj s~adresou \emph{/savci}), pak nepotřebujeme ihned články o~všech dostupných savcích v~řádech několika tisíců. Stačí nám pouze seznam savců a~uživatel si potom zvolí, který konkrétní ho zajímá a~pošle nový požadavek. Je to obdobné, jako v~jazyku Java -- namísto seznamu kopií objektů dostanete seznam referencí. Typické použití propojitelnosti je v~návrhovém vzoru Kolekce nebo u~obrázků v~článku. Příklad reprezentace seznamu savců je uveden níže. \begin{Verbatim} Medvěd hnědý Liška polární \end{Verbatim} To, že odpovědí na požadavek na všechny savce v~encyklopedii není kopie dat všech těchto savců, ale pouze jejich seznam, nám přináší značné výhody. Představte si například, že pro aplikaci Animalia vytváříte desktopovou klientskou aplikaci. Uživateli se po spuštění zobrazí mimo jiné i~standardní grafický prvek stromu, který bude obsahovat v~uzlech názvy jednotlivých savců. Pokud bychom ze serveru získali data všem savců dohromady, ty by měli velikost řádově v~desítkách megabajtů. Start aplikace by se tak výrazně zpomalil. Přitom těžko by uživatel chtěl číst o~všech zvířatech (předpokládejme že v~Animalii je jich několik set) najednou. Zde nastupuje výhoda propojitelnosti. Dostaneme pouze jmenný seznam zvířat spolu s~odkazy, kde se ptát dál. Až si uživatel rozklikne uzel s~nějakým zvířetem, aplikace pošle požadavek na toto konkrétní zvíře. \subsection{Bezpečná metoda} Bezpečná (safe) metoda je taková, u~které je z~hlediska služby jedno, jestli jsme si zavolali vícekrát anebo vůbec. Nemají žádný znatelný vedlejší účinek (například statistiku volání na straně serveru nebereme v~úvahu) a~jejím voláním nejde nic pokazit. Metody \texttt{GET} a~\texttt{HEAD} musí být vždy bezpečné. Tyto metody neimplikují žádné změny ve webové službě a~její klient by proto neměl být zodpovědný za to, že je (například omylem) zavolá vícekrát po sobě. Příkladem funkce spojené s~bezpečnou metodou je \texttt{GET} požadavek na článek v~Animalii. Příkladem funkce, která není bezpečná je odeslání objednávky na internetový obchod metodou \texttt{POST}. \subsection{Idempotetní metoda} Idempotence je slabší podmínka, než bezpečnost. Znamená, že není rozdíl v~tom, jestli jsme metodu zavolali jednou nebo vícekrát po sobě. Idempotetní metody jsou \texttt{PUT} a~\texttt{DELETE} (\texttt{GET} a~\texttt{HEAD} samozřejmě také, jelikož jsou bezpečné). Pokud chceme vytvořit webový zdroj pomocí metody \texttt{PUT}, pak každé další její zavolání se stejným parametrem přepíše již existující zdroj těmi samými daty. Obdobně u~\texttt{DELETE} pokud nějaký zdroj smažeme, pak poslání dalšího \texttt{DELETE} požadavku již nic dalšího v~aplikaci nezmění. Metoda \texttt{POST} obecně idempotetní není. Pokud ji používáme a~potřebujeme ji nějak ošetřit, nabízí se \emph{POST Once Exactly} zmíněné dále. \subsection{POST Once Exactly} Metoda \texttt{POST} není ani bezpečná ani idempotentní. Pokud například posíláme novinový článek na zpravodajskou webovou aplikaci, server většinou vygeneruje nějaké unikátní identifikační číslo (založené například na názvu článku, datu a~počtu již zveřejněných článků) a~vloží jej jako součást adresy našeho článku. Posláním článku znovu (třeba omylem kliknutím na tlačítko Aktualizovat v~prohlížeči) by pak došlo ke zveřejnění duplicity. Tento problém řeší koncept POST Once Exactly. Jedná se o~doporučení jak udělat metodu \texttt{POS} idempotentní. Toto řešení zavádí vlastní hlavičku HTTP požadavku s~názvem \texttt{POE}, jak ukazuje následující příklad. Klient nejdříve vytvoří \texttt{HEAD} nebo \texttt{GET} požadavek (podle možností HTTP knihovny a~implementace na serveru) a~zašle ho na adresu, na kterou by jinak zasílal \texttt{POST} požadavek s~přiloženým článkem. \begin{Verbatim} HEAD /articles HTTP/1.1 Host: www.newspaper.com POE: 1 \end{Verbatim} Hodnota \texttt{1} označuje verzi Post One Exactly specifikace, nikoliv logickou hodnotu. Samotná přítomnost pole hlavičky \texttt{POE} říká, že Post Once Exactly používáme. Server nám pošle odpověď a~v~poli hlavičky odpovědi \texttt{POE-Links} sdělí vygenerovanou cestu adresy, na kterou máme nově poslat článek metodou \texttt{POST}. Odpověď na předchozí požadavek může vypadat následovně: \begin{Verbatim} HTTP/1.1 200 OK POE-Links: /articles/150c48ed \end{Verbatim} Klient si přečte hodnotu pole hlavičky \texttt{POE-Links} a~sestaví novou URI jako \emph{http://} + \emph{adresa serveru} + \emph{nově obdržená cesta}. Na tuto URI pošle \texttt{POST} požadavek s~přiloženým článkem. \begin{Verbatim} POST /articles/150c48ed HTTP/1.1 Host: www.newspaper.com Content-Type: text/plain Content-Length: 1852 POE: 1 ...článek zde... \end{Verbatim} Všimněte si, že tento požadavek opět obsahuje pole hlavičky \texttt{POE}. V~tuto chvíli už server teoreticky nepotřebuje takto explicitní sdělení, jelikož posíláme požadavek na jím vygenerovanou URI. Tu musí mít někde u~sebe označenou jako vygenerovanou za účelem Post Once Exactly, jak záhy uvidíte. Autor návrhu nicméně považuje za účelné, aby bylo pole hlavičky \texttt{POE} přítomno v~každém Post Once Exactly požadavku. Po té, co tento požadavek odešleme si server vyzvedne přiložený článek a~námi zadanou URI zablokuje pro další požadavky (zde vidíte, že si ji musí pamatovat). Tím se zajistí, že na případné poslání duplicitního požadavku se už nereaguje. Pro formu uveďme odpovědi na první zaslání článku a~poté na duplicitní požadavek. \begin{Verbatim} HTTP/1.1 201 Created Location: /articles/29-03-2009-150c48ed \end{Verbatim} Zde se jedná o~klasickou odpověď na metodu \texttt{POST} tak, jak ji známe. Vrácený kód je \texttt{201 Created} spolu s~vyplněným polem hlavičky \texttt{Location}, kde je uvedena výsledná adresa článku. Povšimněte si, že tato výsledná adresa se může, ale nemusí shodovat s~adresou, na kterou jsme posílali náš \texttt{POST} požadavek. Nyní předpokládejme, že uživatel omylem tento \texttt{POST} požadavek pošle znovu. Server zjistí, že zadaná adresa je nyní pro \texttt{POST} blokovaná a~vrátí: \begin{Verbatim} 405 Method Not Allowed HTTP/1.1 Allow: GET \end{Verbatim} Tento návrh zaručuje idempotentnost metody \texttt{POST}. Jeho autor celý tento koncept popisuje v~\cite{POE}, je zmíněn také v~\cite{RESTful Web Services}. Bohužel tento návrh nebyl nikdy uveden do praxe, jeho použití je nutné na straně jak klienta, tak serveru doprogramovat. \subsection{Alternativa k~POE} Alternativou k~návrhu Post Once Exactly je pro každou \texttt{POST} metodu vygenerovat cílovou URI (obdobně jako to dělá POE) a~vrátit ji v~odpovědi přesměrování. Namísto poslání \texttt{POST} požadavku na tuto novou URI pošleme metodu \texttt{PUT} s~přiloženými daty. Tím vlastně nahradíme metodu \texttt{POST} metodou \texttt{PUT}, která je sama o~sobě idempotentní. Tento postup se snadno implementuje, jeho nevýhodou je ovšem dvojité posílání dat na stranu serveru (může vadit u~objemných dat). \subsection{Přetížený POST} Bohužel mnoho HTTP knihoven podporuje pouze metody \texttt{GET} a~\texttt{POST}. Je to poněkud absurdní zvlášť když si uvědomíme, že jednotlivé metody se od sebe liší pouze názvem. I~přesto je podpora ostatních HTTP metod v~jiných jazycích, než je Java, obecně dosti slabá. Vzhledem k~tomu, že webová služba je naprosto nezávislá na programovacím jazyce, snadno může nastat případ kdy nějaký programátor bude chtít vytvořit klientskou aplikaci v~programovacím jazyce, kde až později zjistí, že nemá možnost vytvořit požadavky \texttt{PUT}, \texttt{HEAD} a~\texttt{DELETE}. Proto bylo zavedeno řešení v~podobě přetíženého POSTu, které musí být naimplementováno na úrovni webové služby. Celý návrh je v~koncepci RESTu jakýmsi pomyslným krokem zpět tak, aby byla zajištěna kompatibilita z~ne zcela aktuálními HTTP knihovnami. Namísto posílání požadavků \texttt{PUT}, \texttt{HEAD} a~\texttt{DELETE} se pošle požadavek \texttt{POST}, který má v~query parametru uvedenou reálnou metodu, kterou chceme volat. V~\cite{RESTful Web Services} se doporučuje tento parametr nazvat \texttt{\_method}. Hodnota pro metodu \texttt{PUT} tedy bude \emph{\_method=PUT}. Následující příklad uvádí posílání \texttt{DELETE} požadavku pomocí přetíženého POSTu. \begin{Verbatim} POST /savci/medved_hnedy\codeHighlight{?_method=DELETE} HTTP/1.1 Host: www.animalia.com \end{Verbatim} Jednoho problému jsme se tímto postupem zbavili, aby ale nebylo vše tak snadné, vyvstal nám další. Metoda \texttt{POST} není idempotentní. Tento přístup je tedy spíše jakousi záplatou do doby, než RESTful webové služby proniknou do širší veřejnosti a~stanou se rovnocennou a~uznávanou alternativou k~SOAP webovým službám. Pak by snad dojít k~celkové doplnění HTTP knihoven tak, aby obsahovaly všechny používané HTTP metody. \subsection{Kolekce zdrojů} Velmi častým případem je, že potřebujeme ve webové službě soubor nějakých zdrojů, které k~sobě navzájem patří. Příkladem může být aplikace Animalia, kde chceme zavést soubor všech savců. To se řeší návrhovým vzorem Kolekce (Collection). Každý savec bude vystupovat jako samostatný zdroj a~kolekce všech savců bude také zdroj. Adresa kolekce může být například \emph{/animalia/savci}. Jednotliví savci patří do této kolekce, proto jsou adresy jejich zdrojů hierarchicky pod adresou kolekce. Tedy adresa pro medvěda hnědého může být \emph{animalia/savci/medved\_hnedy}. Každý zdroj, tedy i~zdroj kolekce by měl reagovat na metody HEAD a~GET a~také by měl nabídnout své reprezentace -- alespoň jednu pro lidského uživatele a~alespoň jednu pro programové zpracování. U~metody HEAD je vše jednoduché, ta bude vždy vracet \texttt{200 OK} (kolekce existuje). Odpovědí na metodu GET bude reprezentace kolekce. Pro lidského uživatele můžeme poskytnout třeba HTML stránku s~povídáním o~savcích, jejich roztřídění, návycích a~rozšíření. Pro programové zpracování pak poskytneme XML dokument tvořící seznam všech savců. \subsection{Aliasy a~více adres pro jeden zdroj} Někdy se může hodit, že pro jeden zdroj máme zavedeno více adres. Jelikož každý zdroj má v~RESTu právě jednu adresu, řeší se tento problém pomocí návrhového vzoru Zástupce (Proxy). Vytvoříme nový zdroj s~vlastní adresou, který bude reagovat na jednotlivé metody tak, že vrátí odpověď přesměrování. Jedinou výjimkou může být metoda HEAD, kdy přesměrování můžeme provést implicitně na straně serveru a~vrátit odpověď \texttt{200 OK} nebo \texttt{404 Not Found} podle existence původního zdroje, pro který jsme vytvářeli alias. \subsection{Bezpečnost v~RESTu} Stejně jako u~RPC webových služeb, ani v~RESTu není žádoucí mít některé možnosti přístupné všem uživatelům. Rozlišujeme zabezpečenou metodu webového zdroje (často metody PUT, POST, DELETE) a~zabezpečený celý webový zdroj, tedy takový, který má všechny své metody zabezpečené. Například v~aplikaci Animalia nechceme dovolit, aby běžný uživatel mohl vytvářet, upravovat nebo mazat jednotlivé zdroje zvířat. Tuto možnost ale chceme dovolit správci aplikace. Proto zde budou chráněny metody \texttt{PUT}, \texttt{POST} a~\texttt{DELETE}. V~aplikaci Piggy Bank ale nedovolujeme nechráněnou ani metodu \texttt{GET} vracející informaci o~zůstatku na účtu. Zde bude chráněn celý zdroj reprezentující klientův účet. Většinou jsou pak chráněny i~všechny zdroje z~podstromu hierarchie takovéhoto zdroje. \subsubsection{Uživatelský účet jako zdroj} Připomeňme si pravidlo, že vše v~RESTu je zdroj. Tedy i~uživatelský účet je zdroj. Je potřeba brát na vědomí, že takovýto zdroj vzniká a~může zaniknout v~průběhu času. Tradičně má každý účet přiřazeno uživatelské jméno a~heslo. To přesně zapadá do konceptu REST, jelikož uživatelské jméno tvoří jednoznačnou identifikaci (nelze si založit účet se stejným jménem, jaký je už vytvořený) a~heslo plní funkci autentikace. Demonstrujme si nyní uživatelský účet na příkladu Piggy Bank. Prvním uživatele Piggy Bank se stane pan Pepa. Jakmile se zaregistruje, vytvoří mu webová služba účet na adrese \emph{http://www.piggybank.com/accounts/pepa}. \subsubsection{Přístup na účet} Zabezpečení se v~RESTu realizuje pomocí protokolu HTTP. Celý postup byl popsán v~kapitole \ref{HTTP}, připomeňme si tedy pouze základní princip v~podání RESTové podoby Piggy Bank. Uživatele Pepa se chce podívat na zůstatek na svém účtu. Sestaví (nebo nechá svůj webový prohlížeč sestavit) HTTP požadavek GET a~pošle ji na adresu \emph{http://piggybank.com/accounts/pepa/leftover}. Vrátí se mu odpověď \texttt{401 Unauthorized}. Pan Pepa poté sestaví zprávu znovu a~vyplní autorizační údaje, tedy své uživatelské jméno a~heslo v~podobě base64. \begin{Verbatim} GET /accounts/pepa/leftover HTTP/1.1 Host: www.piggybank.com Authorization: Basic cGVwYTp6ZGVwYQ== \end{Verbatim} Pepa bude muset poslat své autorizační údaje jako součást každého požadavku, který je adresovaný pro jeho účet. To dává smysl, protože protokol HTTP je bezestavový, webová aplikace si tedy nemůže (dokonce nesmí) pamatovat, kdo na účet přistupuje. Naštěstí pan Pepa používá prohlížeč Firefox, který mu umožní zapamatovat si jeho uživatelské jméno a~heslo. To není vyřešeno nijak jinak, než že prohlížeč má oba údaje uložené u~sebe a~vyplní je pro požadavky na účet v~Piggy Bank dopředu. Bezestavovost tak opět není narušena. \subsection{Nákupní košík} V~mnoha materiálech je nákupní košík demonstrací faktu, že bez \emph{sezení} (session -- viz. kapitola \ref{JSP}) se ve webové aplikaci neobejdete. Ovšem sezení dosti zásadně narušují princip bezestavovosti HTTP. V~RESTu je tím pádem jejich použití nepřípustné. Naštěstí existuje funkční způsob jak nákupní implementovat bez nich. Připomeňme si základní myšlenku, že vše v~RESTu je webový zdroj. Tedy: \begin {itemize} \item Internetový obchod je zdroj. \item Zákazník uvnitř obchodu je zdroj (viz. uživatelský účet) \item Jeho nákupní košík je zdroj. \item Každá položka v~tomto vozíku je zdroj. \end{itemize} Navrhnout uživatelský účet jako zdroj včetně zabezpečení už umíme. REST tohoto postupu využívá aby jednoznačně rozlišil čí je který nákupní košík. Není pro to potřeba porovnávat IP adresu ani cookies jako to dělají sezení. Nákupní košík je jednoznačně určen pomocí adresy URI, která obsahuje uživatelské jméno zákazníka. Nevýhodou tohoto přístupu je, že zákazník se musí předem registrovat (je potřeba i~heslo aby mu s~jeho košíkem nemohl manipulovat někdo jiný). Předpokládejme, že zákazník, pan Pepa je v~obchodě reprezentovaný zdrojem s~adresou \emph{/store/pepa} (pro jednoduchost budeme uvádět pouze cestu ke zdroji, nikoliv celou adresu). Jeho košík má adresu \emph{/store/pepa/cart}. Zasláním \texttt{GET} požadavku na adresu košíku zjistíme, co je v~něm uložené. Předpokládejme nyní, že každý artikl v~obchodě má své jednoznačné identifikační číslo a~že pan Pepa má v~košíku uložený předmět s~identifikátorem \emph{124C}. Odpovědí na \texttt{GET} požadavek směřovaný na adresu košíku bude seznam odkazů (pamatujte na propojitelnost) na předměty v~košíku. V~našem případě je to jednoprvkový seznam obsahující adresu \emph{/store/pepa/cart/124C}. Informace o~předmětu zjistíme zasláním \texttt{GET} požadavku na jeho adresu, tedy na \emph{/store/pepa/cart/124C}. Předmět z~košíku odstraníme zasláním \texttt{DELETE} požadavku. Předmět s~kódem \emph{871E} přidáme do košíku zasláním \texttt{PUT} na adresu \emph{/store/pepa/cart/871E}. Při tomto jednoduchém návrhu není možné přidat do košíku nějaký prvek dvakrát. Pokud bychom chtěli tuto možnost, musela by webová služba nějakým způsobem pracovat s~adresami prvků v~košíku. Například na konec identifikátoru vkládat pomlčku spolu s~indexem (např. \emph{/store/pepa/cart/871E-0} a~\emph{/store/pepa/cart/871E-1} pro dva kusy prvku \emph{871E}). %\subsection{Asynchronní operace} %Jednou z~nevýhod protokolu HTTP je, že způsob komunikace požadavek--odpověď je definovaný vždy jako \emph{synchronní}. To znamená, že na každý požadavek musíme v~krátkém čase dostat odpověď. V~opačném případě program pracující s~HTTP zamrzá. U~některých typů webových služeb toto nemusí vyhovovat. Z~povahy řešeného problému může zpracování odpovědi zabírat větší časový úsek (desítky minut až hodiny u~vyřízení objednávky, dny až týdny u~složitých matematických výpočtů ap.). REST, resp. HTTP ovšem pamatuje i~na to. Na požadavek \emph{asynchronní} operace namísto běžného kódu (např. \texttt{200 OK}) vrátí server kód \texttt{202 Accepted} spolu s~vyplněným pole hlavičky \texttt{Location}. Zde je uvedena adresa webového zdroje reprezentujícího výsledek operace. Příklad ukazuje požadavek na algoritmus, u~kterého očekáváme dlouhý výpočetní čas. %\begin{Verbatim} %GET /calc/artificial-ant?generations=1000&pop-size=50000 HTTP/1.1 %Host: www.myexample.com %Content-Type: application/x-www-form-urlencoded %\end{Verbatim} %V~tomto požadavku chceme získat výsledek pro algoritmus umělého mravence (pozn. je to školní úloha genetického programování) se zadanými parametry: 1000 generací a~velikost populace 50000. Řešení této úlohy zabere větší časovou dobu, proto se server nebude snažit čekat na výsledek a~namísto toho nám pošle odpověď: %\begin{Verbatim} %HTTP/1.1 202 Accepted %Location: http://www.myexample.com/calc/12a4dec80 %\end{Verbatim} %V~poli hlavičky \texttt{Location} je serverem vygenerovaná adresa, která bude obsahovat webový zdroj s~výsledkem algoritmu. Dokud není výsledek znám, vrací server pro požadavky na tuto adresu odpověď \texttt{404 Not Found}. Jakmile je výsledek znám, vrátí namísto toho \texttt{200 OK} tak, jak jsme zvyklí. Je celé na zodpovědnosti klienta, aby opakovaně zkoušel, jestli už je dostupný výsledek. Výsledek je pak nutné smazat \texttt{DELETE} požadavkem, jelikož pokud by byl smazán automaticky po nějaké době serverem, nepoznalo by se zvenku, jestli výpočet stále neběží (server by vracel \texttt{404 Not Found}). Stejně tak je možné zastavit celý výpočet zasláním \texttt{DELETE} na adresu výsledku ještě před tím, než je spočítán. Pak se jedná o~stornování operace. Asynchronní operace je nutné implementovat jak na straně klienta, tak na straně webové služby. \subsection{Podmíněný GET a~cache} \label{Conditional GET} Pokud chceme ušetřit objem dat, které protečou při komunikaci mezi serverem a~klientem, můžeme RESTful webovou službu doplnit o~\emph{podmíněný GET}. Ten říká, že chce po serveru získat data pouze, pokud se od nějaké doby změnila (např. webová stránka byla aktualizována). Tato metoda je implementována téměř v~každém moderním prohlížeči. Základem je, že prohlížeč (nebo jiný klient RESTful webové služby) si ukládá odpovědi na \texttt{GET} požadavky do lokální cache jako trojice URI, datum požadavku, tělo odpovědi. Při každém posílání \texttt{GET} požadavku na URI z~cache doplní požadavek o~pole hlavičky \texttt{If-Modified-Since} s~hodnotou nastavenou na datum z~dané trojice. Požadavek na encyklopedii Animalia by pak mohl vypadat takto: \begin{Verbatim} GET /savci/medved_hnedy HTTP/1.1 Host: www.animalia.com If-Modified-Since: Sun, 26 Apr 2009 15:36:31 GMT \end{Verbatim} Server, resp. webová aplikace porovná datum z~pole hlavičky s~datem poslední úpravy požadovaného webového zdroje. Pokud je druhé datum novější, pošle odpověď \texttt{200 OK} s~přiloženými daty tak, jak to znáte. Klient data zpracuje a~přepíše si záznam v~cache. V~opačném případě server vrací odpověď \texttt{304 Not Modified}. V~tomto případě klient použije z~cache. Pokud je požadovaný zdroj na serveru uložen jako soubor, řeší celou proceduru server automaticky. Pokud ale reprezentaci zdroje nějakým způsobem programově sestavujeme, musíme si zajistit porovnání sami. Stejně tak, pokud klientem webové služby bude jiný program než webový prohlížeč, musí v~něm být podmíněný GET implementován (v~opačném případě bude posílat pouze nepodmíněný GET a~nic se tím neušetří). %\subsection{Částečný GET} %Částečný (partial) GET způsob využití metody \texttt{GET} pro získání požadovaných dat rozdělených na části. Namísto zaslání celých dat jednorázově v~odpovědi na \texttt{GET} se klient se serverem dohodnou, že tato data bude server posílat po menších částech. Výhodou je možnost zotavení z~výpadku při komunikaci nebo možnost pauzovat a~poté znovu obnovit stahování. Částečný GET je vhodné použít, pokud chceme klientovi webové služby posílat velká data (např. 500+ MB video se zvířaty v~aplikaci Animalia). Pro obyčejná data malé velikosti, jako jsou obrázky, HTML stránky nebo dokumenty je toto řešení zbytečné. Kompletní postup je následující. Klient pošle na adresu požadovaného zdroje \texttt{HEAD} požadavek. Aplikace vrátí odpověď ve které sdělí velikost dat v~bajtech (pole hlavičky \texttt{Content-Length}). Klient pak pošle \texttt{GET} požadavek na stejnou adresu a~v~poli hlavičky \texttt{Range} specifikuje rozsah bajtů, o~které žádá. V~každém dalším požadavku posune rozsah bajtů a~zasílá je tak dlouho, dokud u~sebe nemá data v~plné velikosti, které pak musí složit dohromady. Poznamenejme, že bajty jsou indexovány od nuly obdobně jako pole v~jazyce Java. Následující příklad uvádí požadavek na prvních 500 bajtů webového zdroje. %\begin{Verbatim} %GET /video/medvedi_01.avi HTTP/1.1 %Host: www.animalia.com %If-Unmodified-Since: Sun, 26 Apr 2009 15:36:31 GMT %Range: bytes=0-499 %\end{Verbatim} %Všimněte si také pole hlavičky \texttt{If-Unmodified-Since} (je obdobné jako pole \texttt{If-Modified-Since} z~\label{Conditional GET}, pouze ve smyslu logické negace). Toto pole s~částečným GETem zdánlivě nesouvisí. Pokud si ovšem uvědomíme, že částečný GET se mimo jiné realizuje kvůli rozložení stahování dat na širší časové období, pak je jeho přítomnost jasná. Potřebujeme se vyhnout situaci, kdy by se data na serveru změnila a~klient si stáhl část starých dat spolu s~částí novou. Takováto data spojená dohromady by nedávala smysl. Kladnou odpovědí serveru na předchozí požadavek je kód \texttt{206 Partial Content} spolu s~vyplněným polem hlavičky \texttt{Content-Range} a~daty přiloženými v~těle odpovědi. %\begin{Verbatim} %HTTP/1.1 206 Partial Content %Content-Type: video/avi %Content-Range: bytes 0-499/512000 %...poslané bajty... %\end{Verbatim} %V~této odpovědi server posílá prvních 500 bajtů požadované AVI reprezentace. Číslo uvedené za lomítkem v~poli hlavičky \texttt{Content-Range} udává celkovou velikost dat (pro kontrolu -- někdy je ale potřeba, protože server nemusí mít implementováno prozkoumání dat metodou \texttt{HEAD}). Pokud by se data na serveru změnila a~mohlo by dojít k~výše zmíněné nekonzistenci, vrátil by server zamítající odpověď \texttt{412 Precondition Failed}. V~takovémto případě by musel klient začít stahovat od začátku. Poznamenejme ještě, že částečný GET bývá implementován na serveru, není potřeba ho doprogramovávat do webové služby. \subsection{Závěr} RESTful webové služby představují kvalitní alternativu k~masově rozšířeným RPC webovým službám. Mezi hlavní výhody patří adresovatelnost, propojitelnost a~také hierarchie webových zdrojů. Zároveň RESTful webové služby připomínají osvědčený koncept objektově orientovaného programování, lze tedy do budoucna očekávat rozvoj celého~návrhu ve formě návrhových vzorů, testování ap. Mezi nevýhody patří (ne vlastní vinou) místy slabá podpora v~HTTP knihovnách. Další nevýhodou je poněkud přílišná obecnost a~volnost v~návratových kódech odpovědí. Je velmi obtížné naprogramovat plně automatizovaného klienta, který by byl schopen správně reagovat na všechny návratové kódy, navíc ještě v~kontextu událostí. Přesto lze říct, že RESTful webové služby si získávají stále větší popularitu, obzvláště u~nezávislých vývojářů. Použitá literatura:\\ \cite{RESTful Web Services} \emph{RESTful Web Services}