JavaScript na serveru: REST API

node.js logo

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.

Seriál: Node.js - s JavaScriptem na serveru (13 dílů)

  1. JavaScript na serveru: Začínáme s Node.js 23.11.2010
  2. JavaScript na serveru: Patří budoucnost Node.js? 21.9.2012
  3. JavaScript na serveru: Architektura a první Hello World 5.10.2012
  4. JavaScript na serveru: moduly a npm 12.10.2012
  5. JavaScript na serveru: začínáme programovat e-shop 19.10.2012
  6. JavaScript na serveru: MongoDB, Mongoose a AngularJS 26.10.2012
  7. JavaScript na serveru: Testování a kontinuální integrace 2.11.2012
  8. JavaScript na serveru: REST API 9.11.2012
  9. JavaScript na serveru: implementace REST API 16.11.2012
  10. JavaScript na serveru: nástroje a dokumentace 23.11.2012
  11. Začínáme s AngularJS 30.11.2012
  12. AngularJS direktivy a testování 7.12.2012
  13. JavaScript na serveru: CoffeeScript a šablonovací systémy 14.12.2012

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!

Jakub pracoval na několika zajímavých projektech, za nejvýznamnější považuje vytvoření e-commerce řešení Shopio.cz. Poslední rok se plně věnuje Node.js, frameworku AngularJS a NoSQL databázím.

Komentáře: 16

Přehled komentářů

langpa POST vs PUT
langpa Re: POST vs PUT
jistr Re: POST vs PUT
langpa polling
langpa Re: polling
Alblaho Není serizál zbytečně rozvleklý?
Jakub Mrozek Re: Není serizál zbytečně rozvleklý?
Fen Re: Není serizál zbytečně rozvleklý?
http://xdexter.id.seznam.cz/ Node.js autorizace a autentizace
Jakub Mrozek Re: Node.js autorizace a autentizace
langpa Testování REST API
Jakub Mrozek Re: Testování REST API
langpa Re: Testování REST API
Jakub Mrozek Re: Testování REST API
langpa Re: Testování REST API
M3dard děkuji za článek a dotaz
Zdroj: http://www.zdrojak.cz/?p=3737