Přejít k navigační liště

Zdroják » Různé » JavaScript na serveru: REST API

JavaScript na serveru: REST API

Články Různé

Další dva díly seriálu o Node.js budou věnovány tvorbě REST API. V dnešním díle se podrobněji podíváme na doporučené postupy pro tvorbu API. Příště popsanou teorii uvedeme do života.

Nálepky:

REST na Zdrojáku již jeden článek vyšel, takže je-li pro vás tento pojem neznámý, určitě si přečtěte článek od M. Malého REST: Architektura pro webové API.

Ačkoliv REST není přímo s Node.js nijak spjat, myslím si, že je dobré věnovat mu trochu více prostoru, aby bylo v pozdějších dílech seriálu čtenáři hned jasné, proč je třeba vrácen právě daný HTTP kód a ne jiný. Kromě toho je REST API jedna z oblastí, pro kterou se Node.js používá velmi často.

V tomto článku se nebudu věnovat autorizaci a autentizaci ani kešování obsahu. Obě témata si zaslouží samostatný díl a budeme se jim věnovat v pozdějších dílech seriálu.

Proč REST API

Pokud budu uvažovat náš vyvíjený e-shop, může se REST API využít při mnoha příležitostech:

  1. Webové rozhraní pro nákup v e-shopu. V našem případě řešeno přes HTML5 a framework AngularJS.
  2. Administrační rozhraní. Velmi často provozuje jeden zákazník více e-shopů, takže může požadovat jedno administrační rozhraní pro všechny e-shopy.
  3. Import dat. Téměř všechny e-shopy importují produkty z nějakých externích systémů. Buď se tento systém sám na náš e-shop napojí, nebo vytvoříme „můstek“, který data z daného systému překlopí přes API do našeho systému.
  4. Export dat. Každý e-shop potřebuje data někam exportovat, např. do účetního systému.
  5. Různé další projekty, které potřebují s e-shopem komunikovat. Žijeme v době startupů, kdy i nejjednodušší problém řeší mnoho zajímavých projektů. Ty však potřebují nějak automatizovaně s naším e-shopem komunikovat.
  6. Verze pro smartphony a tablety. Můžete chtít speciální mobilní verzi pro Android či iPhone, která ale potřebuje odněkud získávat data. Máme-li např. e-shop pro prodej jízdenek, budeme určitě chtít i mobilní verzi.
  7. Mnoho dalších možností, affiliate systémy nebo třeba reklamní aplikace s katalogem mobilních telefonů. A data do aplikace budeme importovat z našeho e-shopu s telefony (samozřejmě v detailu telefonu nezapomeneme na tlačítko „Koupit“).

Nejlepší postupy pro REST

Dále popisuji základní doporučení návrhu relevantní k vyvíjeném e-shopu. Máte-li zájem o hlubší prozkoumání problematiky, pak lze doporučit knihu REST API Design Rulebook nebo REST tutoriál.

Bohužel každá kniha věnující se REST se v různých oblastech do značné míry rozchází. Podobně je tomu v případě API známých serverů typu Facebook či Twitter. Následující řádky obsahují mix doporučení a postupů, které považuji za nejlepší a nejjednodušší.

HTTP metody

Správné použití HTTP metod je popsáno v odkazovaném článku, zde jen zopakuji, že metoda GET se používá pouze pro získávání dat, metoda POST se nejčastěji používá pro vkládání, PUT pro editaci a DELETE pro mazání.

HTTP kódy

Protokol HTTP obsahuje celou řadu stavových kódů, které se používají pro specifické události.

200 OK

Nejpoužívanější HTTP kód. Je vrácen v případě správného zpracování HTTP požadavku. HTTP odpověď by měla obsahovat další data. Pokud chceme pouze oznámit, že požadavek byl úspěšně zpracován a žádná další data odesílat nechceme, použije se HTTP kód 204. Kód 200 nikdy nesmí být navrácen v případě, že došlo k chybě (často se tak však mylně používá).

201 Created

Používá se při vytvoření nového zdroje. Tedy když úspěšně vytvoříme nový produkt přes POST/PUT /products, vracíme kód 201 a odkaz na nově vytvořený zdroj v hlavičce Location.

202 Accepted

Používá se tehdy, začne-li zpracování nějaké dlouhotrvající operace. Místo toho, abychom čekali na dokončení operace (může trvat velmi dlouho), vrátíme HTTP kód 202. Tím říkáme, že požadavek je validní a jeho zpracování bylo úspěšně zahájeno. Neříká ale nic o tom, jak operace dopadla.

204 No Content

Používá se podobně jako HTTP kód 200, ale nevrací žádný obsah. Používá se např. při mazání zdroje. Když smažeme nějaký produkt, vrátíme kód 204, kterým říkáme, že byl úspěšně z databáze odstraněn.

301 Moved Permanently

Říká, že zdroj byl přesunut na novou adresu. Rozhodneme-li se změnit URL produktu v e-shopu, vrátíme tento kód a hlavičku Location s novou adresou. Prohlížeč by měl po obdržení kódu 301 automaticky aktualizovat všechny reference, takže na původní URL už dotaz nepůjde.

303 See Other

Říká, že požadavek byl zpracován, ale nevrací informace o výsledku zpracování, pouze v hlavičce Location uvádí adresu, kde je možné podrobnější informace o zpracování získat. Hodí se to např. u mobilních aplikací, kdy je potřeba hlídat každý přenesený byte. Nebo pokaždé, když je potřeba přesměrovat z webového formuláře (po POSTu) na nějakou cílovou stránku, třeba po přihlášení.

304 Not Modified

Souvisí s kešováním obsahu. Server tímto kódem říká, že prohlížeč má u sebe aktuální verzi dokumentu a není potřeba, aby stahoval stejnou verzi. Odpověď tedy neobsahuje tělo.

307 Temporary Redirect

Říká, že server aktuálně nemůže zpracovat daný požadavek a místo toho v hlavičce Location posílá adresu, na které má být požadavek o zpracování znovu zaslán.

400 Bad Request

Používá se pro oznámení chyby, na který nelze použít jiný 4×x status.

401 Unauthorized

Neautorizovaný přístup. Uživatel zadal buď chybné přihlašovací údaje, nebo nezadal přihlašovací údaje vůbec.

403 Forbidden

Uživatel požaduje informace o zdroji, ke kterému nemá přístup.

404 Not Found

Uživatel se dotazuje na URL, která neexistuje a nikdy neexistovala. Kód 404 se používá i v situaci, kdy samotné prozrazení existence obsahu na URL má nepříznivý vliv na bezpečnost. Proto je v některých případech legitimní odpovědět místo kódu 401 či 403 tímto kódem.

406 Not Acceptable

Uživatel požaduje vrátit data ve formátu, který server nedokáže obsloužit. Souvisí s hlavičkou Accept, ve které může např. uživatel říct, že chce data ve formátu XML, server je však dokáže odeslat jen ve formátu JSON. Tehdy vrátí kód 406.

409 Conflict

Používá se tehdy, pokud by zpracování požadavku uvedlo aplikaci do nekonzistentního stavu. Chce-li uživatel smazat dokument, na kterém jsou závislé jiné dokumenty, vrátíme tento kód. Může se hodit třeba při požadavku na smazání produktu, který právě někdo nakupuje.

410 Gone

Říkáme, že byl dokument trvale smazán. Pokud víme, že na této adrese něco existovalo, a už to zde není, vracíme 410, nikoliv 404. Na dané adrese by se již nikdy nemělo nic nacházet.

415 Unsupported Media Type

Podobný status jako HTTP 406, ovšem zde říkáme, že uživatel zaslal data ve formátu, který nejsme schopni zpracovat. Např. nám uživatel zaslal data v XML, server ale umí zpracovat jen JSON.

500 Internal Server Error

Chyba je na straně serveru a nesouvisí přímo s obsahem požadavku uživatele. Např. dojde k vyhození výjimky, která nebyla zachycena a zpracována.

HTTP kódů je o něco více, jejich kompletní přehled najdete na české Wikipedii.

Struktura URL

URL má jednoduchý a intuitivní formát a může odkazovat na zdroj, který pracuje buď s celou kolekcí, nebo s konkrétním elementem (dokumentem) kolekce. 

Odkaz na celou kolekci produktů může vypadat takto:

example.com/products

Odkaz na konkrétní element produktu s ID 123 takto:

example.com/products/123

Chceme-li se odkázat na dokument, který závisí na jiném dokumentu a nemůže existovat zvlášť, přidáme do cesty i rodičovský dokument. Např. varianty produktů nemohou existovat samostatně, takže na variantu s ID 456 produktu ID 123 se můžeme odkázat takto:

example.com/products/123/variants/456

Kromě práce se zdroji můžeme chtít provádět na kolekci nebo elementu nějakou akci. Např. URL pro vygenerování faktury pro objednávku číslo 123 může mít adresu:

example.com/orders/123/generate

Akce se bude volat metodou HTTP POST, protože žádná akce GET nesmí data měnit.

Názvosloví

Pro názvy kolekcí se používají vždy podstatná jména v množném čísle a nejlépe v anglickém jazyce. Pro názvy akcí na kolekcích či dokumentech se naopak používají slovesa.

Pro oddělení slov v názvech kolekcí či dokumentů se používají pomlčky. Pro názvy atributů se vždy používá tzv. “cammelCase”, tedy např. dateCreated. Podtržítka se nepoužívají nikdy.

Formát komunikace

Nejčastěji se dnes komunikuje přes JSON, který se doporučuje používat jako výchozí formát. Vedle toho se velmi často používá XML. Pokud chce uživatel vrátit odpověď v konkrétním formátu, zasílá se HTTP hlavička Accept.

Filtrování

Pro filtrování výsledků je nejjednodušší přidat požadované filtry do URL, tedy chceme-li např. vrátit produkty s cenou 1000, mohlo by URL to vypadat takto:

example.com/products?price=1000

Stránkování

Pro stránkování lze přidat do URL parametr limit (říká, kolik záznamů se má vrátit) a offset (od kterého záznamu). Tedy chceme-li vrátit 25 produktů od prvního záznamu, můžeme použit tento dotaz:

example.com/products?limit=25&offset=0

Zde je potřeba upozornit, že je vždy nutné validovat požadovaný rozsah a nastavit maximální rozsah, který můžeme vrátit.

Kromě toho je možné pro stránkování použít HTTP hlavičku Range a v odpovědi Content-Range.

Řazení

Pro řazení se použije v URL parametr sort, který obsahuje pole, podle kterých se mají dokumenty seřadit. Pokud chceme použít opačné pořadí, před název pole se vloží znak “-”.

Chcete-li tedy vrátit všechny produkty podle jejich ceny (price) a dále v opačném pořadí podle názvu (name), pak dotaz může vypadat takto:

example.com/products?sort=price,-name

Pole

Chceme-li vrátit jen určitá pole (sloupce), použije se parametr fields. Chceme-li tedy vrátit název produktu, perex a cenu, mohl by dotaz vypadat takto:

example.com/products?fields=name,perex,price

Verzování API

API je dobré hned od začátku verzovat a nejčastěji se používá prefix v + číslo verze. Takže např. kolekce s produkty bude dostupná na adrese:

example.com/v1/products

Umístění API

Nejčastěji se umisťuje na samostatnou subdoménu api, tedy např. api.example.com. V případě naší aplikace pro zjednodušení nebudeme vytvářet samostatnou subdoménu a API bude dostupné přes prefix /api, tedy produkty získáme na adrese:

example.com/api/v1/products 

Dokumentace API

Dokumentace k API se doporučuje umísťovat na samostatnou subdoménu developers: developers.example.com.

Kromě toho je dobré přidat přesměrování z adres dev.example.com a developer.example.com.

Zpracování chyb

Nastane-li chyba, v HTTP odpovědi zasíláme vždy parametr message s popisem chyby. Volitelně pak parametr code (interní číslo chyby) nebo type (pojmenování chyby) a odkaz na podrobnější informace v parametru moreInfo. Tedy zadá-li např. uživatel v dotazu, že chce vrátit pole “perex”, které však nevracíme, vrátíme HTTP kód 400 s tímto popisem chyby:

{
  code:  1234,
  message: "Požadované pole 'perex' neexistuje.",
  moreInfo: "http://developers.example.com/errors/1234"
}

Co dále

V příštím díle dnes zmíněnou teorii uvedeme do praxe a upravíme e-shop tak, aby zmíněná pravidla plně respektoval.

Na tvorbě tohoto článku se svými připomínkami podílel také Pavel Lang (github). Díky!

Komentáře

Subscribe
Upozornit na
guest
16 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
Pavel Lang

Jde o to, že by s PUT by nemělo spojeno moc magie, prostě vytvoří nebo nahradí obsah tak jak je.
POST oproti tomu může magicky působit, protože může k resource přistupovat inkrementálně, přidávat a odebírat tagy a pod.

Toto je přibližný a doplněný překlad z stackoverflow­.com. Resource nepřekládám… (dá se překládat jako zdroj/zdroje, ale je to zbytečně matoucí)

POST:
Používá se k úpravě nebo aktualizaci existujícího resource:
POST /otazky/<existujici-otazka> HTTP/1.1
Host: blahblah.cz

Ne však k vytvoření neexistujícího resource, toto je chybné použití:
POST /otazky/<nova-otazka> HTTP/1.1
Host: blahblah.cz
Pokud resource na URL není ještě vytvořen, neměla by se POST metoda používat k vytvoření. Takový požadavek na server by měl být zodpovězen jako 404 Not Found.
Na druhou stranu stejný PUT požadavek na server by měla resource vytvořit a odpovědět kódem 201 Created (nebo 303)

Je ale možné udělat něco takového pro vytvoření resource pomocí POST:
POST /otazky HTTP/1.1
Host: blahblah.cz
Rozdíl je v tom, že v tomto případě není jméno resource uvedeno v URL. V tomto případě by měl server odpovědět URL na které se vytvořený resource nachází.

PUT:
Používá se k:
– vytvoření, pokud resource na URL neexistuje, server odpoví 201 Created
– přepsání, úplnému nahrazení resource, pokud již existuje, server odpoví 202 Accepted

Pro vytvoření resource:
PUT /otazky/<nova-otazka> HTTP/1.1
Host: blahblah.cz

Pro přepsání existujícího resource:
PUT /questions/<e­xisting_questi­on> HTTP/1.1
Host: wahteverblahblah­.com

Jakube, omlouvám se jestli jsem to nezachytil, když jsem článek revidoval, tak alespoň tady… :-)

Pavel Lang

Jenom ještě dodám, že RESTfull APIs nejsou exaktní věda :-) Prostě je potřeba mít trochu citu, alespoň stručnou dokumentaci a hlavně integrační testy!

jistr

Souhlasím, pouze bych opravil toto:

„PUT — přepsání, úplnému nahrazení resource, pokud již existuje, server odpoví 202 Accepted“ S tímto nesouhlasím, PUT by měl většinou odpovídat 200 OK, pokud server operaci dokončil před odesláním odpovědi klientovi.

Kód 202 Accepted se používá, pokud operace nebyla dokončena před odesláním odpovědi, a je jedno jestli to byl POST, PUT nebo DELETE. Kód 202 naznačuje klientovi, že poslal správně formulovaný požadavek, ale že operace není ještě hotova. Klient pak většinou používá periodický polling ke zjištění, zda už operace proběhla.

Pavel Lang

Díky za připomínku, zní to logicky. Jen by mě zajímalo jak probíhá následný polling. Klient pošle GET požadavek a dostane celý obsah, nebo může posílat HEADER, pokud ho zajímá pouze stavový kód?

Pavel Lang

Samozřejmě ne HEADER ale HEAD… nevím, měl asi jsem bug v idei…

Alblaho

Seriál se mi líbí, ale mám pocit, že zbytečně odbíhá od tématu. Pitvání různých HTTP kódů mi přijde zbytečné. Chci více nodejs, méně věcí kolem.

Jinak „sort“ je přesnější překládat jako řazení. Třídění je rozklad množiny do tříd.

Fen

Ja si zase myslim, ze je to pojato vhodne. Jen je skoda toho rozdeleni na 2 samostatne clanky. Priklanel bych se i k brzkemu popisu autorizace a autentifikace :) Serial se mi dost libi (to poznam tak, ze netrpelive cekam, az vyjde dalsi dil ;D), takze jen tak dal.

http://xdexter.id.seznam.cz/

Dobrý den,
v článku zmiňujete, že se budete věnovat v dalších dílech autorizaci a autentizaci. Chtěl bych se zeptat, jaké moduly (knihovny) na autorizaci a autentizaci používáte (dříve jste se již zmínil o Passport a Everyauth)?

Děkuji.

Pavel Lang

Ještě zde zmíním výborný český (nikoli počeštěný) startup na testování RESTfull APIs: apiary.io.
Určitě stojí za to vyzkoušet.

Pavel Lang

Ačkoli naši čeští kluci odvedli skvělou práci, nemyslím si, že by se o jejich výtvor měl opírat nějaký další článek v seriálu. Paralelně o tom může napsat někdo jiný (že Adame :-) ), ale myslím, že už zevrubným popisem RESTfull API se seriál zaměřený primárně na node odebírá trochu jiným směrem než měl cílit a to je trochu škoda, ne pro teď, ale jako „návod“ někdy v budoucnu tím trochu trpí.

Pavel Lang

Ok :-)

M3dard

V současné době se s použitím REST architektury setkávám stále častěji a začínám jí i implementovat do svých aplikací.
Proto mi pomohl hezký seznam kódů používaných pro odpověď. Jak jsem zjistil, používal jsem některé špatně.
Zajímalo by mě také, zda pro zvolení formátu komunikace není jednoduší používat na konci URL příponu formátu „.json“ nebo „.xml“. Protože použití hlavičky s accept požadavkem se mi zdá, hlavně při GET dotazech, u kterých není potřeba autorizace, zbytečně složité.
Jinak moc děkuji za hezký článek, který teda toho neměl moc společného s nodeJS :-))

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.

Pocta C64

Za prvopočátek své programátorské kariéry vděčím počítači Commodore 64. Tehdy jsem genialitu návrhu nemohl docenit. Dnes dokážu lehce nahlédnout pod pokličku. Chtěl bych se o to s vámi podělit a vzdát mu hold.