Architektura aplikace
E-shop popsaný v minulém díle budeme vytvářet způsobem, který je odlišný od klasických způsobů tvorby aplikací. Středem celé aplikace bude REST API, se kterým budou komunikovat ostatní části, v tomto případě rozhraní k administraci a rozhraní k uživatelské části. Tímto způsobem je projekt rozdělen na tři samostatné části, jak ukazuje následující schéma:
Striktní oddělení tří částí přináší jednu velkou výhodu: můžeme vytvořit nejprve celou uživatelskou část, aniž bychom napsali jediný řádek kódu na straně serveru v Node.js.
Problémy při návrhu „klasickým“ způsobem
Všichni nejspíš máme tu zkušenost, že na papíře je možné vše hezky plánovat, ovšem jakmile se aplikace začne reálně programovat, dochází k četným změnám, které je ovšem nutné komunikovat s klientem, což stojí hodně času. A i když všechny změny klient odsouhlasí, jakmile je mu aplikace předvedena, okamžitě začne požadovat množství úprav. A úpravy v již naprogramovaném (hotovém) e-shopu stojí mnohem více času a peněz než úpravy „na papíře“.
Proto jsou zde různé agilní metodiky, které se snaží s klientem práci průběžně komunikovat a rozdělit projekt na menší iterace a vyhnout se tomu, že na konci práce nedostane to, co opravdu potřebuje. Tímto se ale nevyhneme četným úpravám kódu, s čímž některé metodiky již přímo počítají.
Abychom minimalizovali nutnost změn, snažíme se od klienta získat nejkvalitnější informace o tom, co vlastně potřebuje a z nich pak vytváříme návrh, který se mu snažíme co nejpřesněji odprezentovat (tímto tématem se zabývá skvělá kniha Požadavky na software od Karla E. Wiegerse, velmi doporučuji). Používá se k tomu např. prototypování.
Vůbec nejlepší by bylo, kdyby klient viděl přímo šablony s reálnými daty a mohl s nimi pracovat jako s klasickým webem. Viděl by již funkčnost reálného e-shopu, který poté dostane, a je tedy velmi pravděpodobné, že by dokázal většinu změn oproti návrhu odhalit již zde. Zároveň ale nechceme trávit žádný čas navíc něčím, co je pouze pro prezentaci a co pak zahodíme. A právě aplikace s REST architekturou takový způsob návrhu umožňuje.
REST API a Apiary
Nejprve vytvoříme celou uživatelskou část v AngularJS. Se serverem bude komunikovat pouze pomocí REST API. Protože API budeme programovat až po tvorbě uživatelské části, využijeme nástroj Apiary, který na předem dané HTTP požadavky bude odpovídat předdefinovanými HTTP odpověďmi. Z toho pak dostaneme také data pro lokální testování a vždy aktuální dokumentaci. REST API a Apiary se věnoval 8., 9. a 12. díl seriálu o Node.js.
Podobným způsobem budeme vytvářet i administraci (kterou může programovat i jiný vývojář zároveň s uživ. částí) i případně ostatní projekty, které budou získávat data také přes API (třeba nějaká mobilní aplikace).
Struktura uživatelské části
Při tvorbě návrhu budeme hledat nejjednodušší řešení, které splní zadané požadavky. Sepišme si seznam stránek, které se budou zobrazovat v uživatelské části:
- Úvodní stránka
- Detail kategorie
- Detail produktu
- Detail stránky
- Vyhledávání
- Košík
- Výběr dopravy a platby (1. krok objednávky)
- Zadání uživatelských dat (2. krok objednávky)
- Potvrzení objednávky (3. krok objednávky)
Na těchto stránkách budeme zpracovávat několik operací, kvůli kterým bude potřeba komunikovat s API:
- získání seznamu kategorií pro menu,
- získání seznamu stránek (FAQ, obchodní podmínky ap.) pro další menu,
- získání detailu stránky,
- získání několika produktů pro úvodní stránku,
- získání produktů pro danou kategorii,
- získání dat pro detail produktu,
- hledání produktů na danou frázi,
- kontrola a vložení objednávky do databáze.
Všechny ostatní operace budeme zatím řešit na straně klienta. V prohlížeči bude uložen i obsah košíku, nicméně před vložením do databáze bude objednávka samozřejmě zkontrolována.
Podíváme-li se na operace, které budou zpracovány přes API, můžeme si všimnout, že s výjimkou vyhledávání a vkládání do databáze se dají všechny výborně kešovat. Třeba taková stránka FAQ se bude měnit jen výjimečně, proto můžeme na serveru přímo vygenerovat a uložit soubor faq.json a případný dotaz na FAQ pak může rovnou zpracovat třeba nginx a požadavek nedojde vůbec k Node.js. Pokud pro samotné vyhledávání použijeme specializovanou databázi jako ElasticSearch, se kterou se komunikuje také přes REST API, pak se bude z pohledu uživatelské části komunikovat s databází pouze při vložení objednávky do databáze. Celý e-shop je tak vlastně statický web složený z HTML šablon a JSON souborů.
Návrh REST API
Dále budeme navrhovat samotné API z pohledu uživatelské části webu. Každá z URL bude prefixovaná řetězcem /api/v1
. Všechna níže uvedená URL se týkají pouze komunikace s API, nejde o URL, která uvidí zákazník.
Získání seznamu kategorií pro menu
Budeme chtít získávat všechny kategorie ve stromové struktuře, takže dotaz bude stejný jako v administraci:
GET /categories
Jako návratovou hodnotu můžeme očekávat pole se všemi kategoriemi na nejvyšší úrovni (případné podkategorie budou vráceny jako položka rodičovské kategorie). Jedna vrácená kategorie bude mít tyto atributy:
- Název (name)
- URL (url)
- Podkategorie (children, pole potomků, opět mohou mít položky název, URL a podkategorie).
Získání seznamu stránek
Pro získání všech stránek použijeme klasický HTTP GET požadavek a přidáme také seznam polí, které chceme vrátit (jinak bychom měli vrátit všechny):
GET /pages?fields=name,url
Návratovou hodnotou je pole se všemi stránkami, přičemž každá obsahuje název a URL. Parametr fields
budeme přidávat i u dalších adres, pokud budeme chtít vrátit jen určité položky.
Získání detailu stránky
Získání jedné stránky je jednoduchý dotaz:
GET /pages?url={url}
Pokud stránka s touto URL neexistuje, bude vrácen HTTP kód 404, jinak HTTP kód 200 a v odpovědi budou tyto položky:
- Název (name)
- URL (url)
- Text (text)
Adresa nemá formát /pages/{id}
, protože při HTTP požadavku na danou stránku nemáme k dispozici ID stránky. To budeme mít až v administraci, proto má dotaz na stránku tento formát.
Získání produktů pro kategorii
V kategorii se budou vždy vypisovat jen produkty z dané kategorie.
GET /products?category={kategorie}&limit={kolik}&offset={odkud}
Jako návratovou hodnotu očekáváme pole se všemi produkty, přičemž jeden vrácený produkt bude obsahovat tyto položky:
- Název (name)
- URL (url)
- Krátký popisek (perex)
- Fotografie (photo)
- Výrobce (producer)
- Kategorie (category, název a url kategorie)
- Dostupnost (availability)
- Cena vč. DPH (price)
- DPH (vat)
URL by také mohlo být /categories/{id kategorie}/products
. Protože však později budeme přidávat sofistikovanější filtrování produktů v kategorii, bude výhodnější nechat tento formát URL.
Získání produktů pro úvodní stránku
Na úvodní stránce se budou vypisovat produkty, které jsou označeny atributem homepage. Mezi požadavky tento atribut uveden nebyl a vznikl, až když jsme začali navrhovat úvodní stránku.
GET /products?homepage=true
Jako návratovou hodnotu budeme očekávat pole všech produktů s tímto atributem. Jeden vrácený produkt bude mít stejný formát jako produkty vrácené v kategorii.
Získání produktu pro detail produktu
V detailu produktu budeme vracet téměř všechny atributy, které máme u produktu uloženy:
GET /products?url={url}
V případě, že produkt nebude na dané URL nalezen, bude vrácen HTTP kód 404, jinak očekáváme HTTP kód 200 a tělo odpovědi bude obsahovat tyto položky:
- Název (name)
- URL (url)
- Kód (code)
- Krátký popisek (perex)
- Dlouhý popisek (text)
- Fotografie (photos, pole)
- Parametry (parameters, pole)
- Výrobce (producer)
- Kategorie (category, název a url kategorie, pole)
- Dostupnost (availability)
- Cena vč. DPH (price)
- DPH (vat)
Vyhledávání produktů
Vyhledávat budeme pouze na kolekci s produkty. URL bude vypadat takto:
GET /products?q={dotaz}&limit={kolik}&offset={odkud}
Jako návratovou hodnotu budeme očekávat:
- celkový počet nalezených produktů (count)
- vrácené produkty dle stránkování (jeden záznam bude mít stejný formát jako v případě získání produktů pro kategorii)
Vložení objednávky do databáze
Obsah košíku bude uložen na straně klienta (v prohlížeči) a vložení objednávky proběhne metodou POST:
POST /orders
Jako obsah požadavku zašleme ve formátu JSON data z nákupního košíku (kód produktu, počet ks), zadanou doručovací a případně kontaktní adresu a typ dopravy a platby.
V případě, že bude objednávka v pořádku vložena do databáze, bude vráceno číslo vytvořené objednávky. V opačném případě bude navrácena informace o chybě, kvůli které nebylo možné objednávku zpracovat.
Co dále
V dalším kroku vytvoříme rozhraní API v Apiary a následně základní podobu všech šablon, které pak rozhýbeme pomocí frameworku AngularJS.
Na tvorbě tohoto článku se svými připomínkami podílel také Pavel Lang. Díky!
Přehled komentářů