Jetstack
Zpět na blog Blog

REST API – celá aplikace přes HTTP

Publikováno 1. listopadu 2022

Technická ilustrace k článku Jetstacku

Každá firemní aplikace se dřív nebo později musí propojit s něčím dalším. Veřejný web, který má zobrazovat aktuální katalog produktů. Mobilní aplikace, která je vlastně jen odlehčený klient nad stejnými daty. Účetní systém, který čeká na měsíční uzávěrkový export. Datový sklad, který chce mít včerejší transakce k dispozici do rána. Partnerský portál, který čte záznamy přes API bránu. Jestli taková integrace zabere hodiny, týdny, nebo skončí opuštěná, skoro vždy závisí na kvalitě API, nad kterým vzniká. To naše je stavěné tak, aby z platformy nebyl uzavřený ostrov dat, ale propojovací uzel.

Základ je pokrytí. Přes HTTP je dostupný každý typ – systémové i ty, které si prostředí nadefinuje samo – a stejně tak uživatelé, soubory, dotazy i spouštěče automatizací. Pokud něco v platformě existuje a uživatel s tím může pracovat v rozhraní, integrace se k tomu dostane přes API. To je ten příslib: většina entit se řídí stejným jednotným vzorem, jen pár speciálních kolekcí – štítky a oznámení – se chová po svém. Když je funkce k dispozici, je k dispozici i endpoint.

Volnost ve volbě identifikátoru je drobnost, která ale hodně usnadní život. Na záznam se dá odkázat přes jeho UUID, přes číselný identifikátor nebo přes systémový název. To se hodí proto, že integrace si často nesou vlastní identifikátory – číslo objednávky u partnera, externí ID zákazníka – které na straně prostředí odpovídají systémovým názvům. Požadavek PATCH na /api/v1/collection/customers/acme-industries je platný, pokud je acme-industries systémový název záznamu, takže odpadá obvyklá integrační otrava s udržováním paralelní převodní tabulky identifikátorů.

Filtry používají stejný jazyk výrazů, jaký tvoří tvůrce dotazů v rozhraní, jen serializovaný do řetězce dotazu. Na hranici integrace tak nemusíte slevit ze složitosti: vnořené podmínky, větve OR, odkazy na poddotazy, procházení vazeb i výrazy pracující s daty – to všechno je dostupné přímo z URL. Pokročilé filtrování není výsada rozhraní, což v praxi znamená, že se externí klient může ptát stejně přesně jako zkušení uživatelé platformy, a to bez reportovací vrstvy mezi tím.

Čtení dotváří řazení, stránkování a výběr polí. Řadit lze podle více polí se stejným chováním jako v rozhraní. Stránkování má rozumné horní meze, aby nedošlo k nechtěnému projetí celé tabulky. Výběr polí funguje ve třech režimech – showFields pro minimální odpověď, hideFields pro vynechání pár nákladných vlastností a wrapFields pro zanoření souvisejících dat – takže si konzument API vezme přesně tolik dat, kolik potřebuje, a nedostane dva megabajty, když chtěl jen jméno a stav.

Výchozí řazení objektů je malá věc, která volajícímu ušetří jeden parametr. Typy, které mají definované vlastní kanonické pořadí – pozici priority u úkolu, pořadí u položky – vracejí své záznamy v tomto pořadí automaticky, takže klient, který chce "přirozený" pohled, nemusí řazení nijak zadávat. Když potřebuje něco jiného, explicitní řazení výchozí nastavení přebije.

Zápis je místo, kde se API vyplatí promyslet podruhé. Vytvoření, úprava, částečná úprava (patch) i mazání se chovají tak, jak byste čekali. Standardní vzorce užitečně rozšiřují dva operátory. += přidá hodnoty do kolekce, aniž by přepsal ty stávající – připojení souboru, přidání účastníka, rozšíření seznamu – což je operace, kterou při aktualizaci většina integrací ve skutečnosti chce, ale bez komplikovaného čtení-úpravy-zápisu ji málokdy dostane. +== je jeho o něco přísnější příbuzný, který navíc hlídá jedinečnost: přidej tuto hodnotu, pokud tam ještě není. Právě v tom je rozdíl mezi integrací, která respektuje souběžné úpravy, a tou, která je přepíše.

Druhá funkce zápisu, která stojí za zmínku, je patch podle odkazu. Integrace, která dostává aktualizace klíčované externím identifikátorem – číslem objednávky partnera, ID záznamu v nadřazeném systému – může cílový záznam upravit přímo podle tohoto identifikátoru, aniž by si nejdřív musela dohledávat interní identifikátor. Platforma odkaz vyhodnotí, provede úpravu a vrátí aktualizovaný záznam. Ze dvou volání je tak jedno a spolu s tím mizí celá jedna třída souběhových chyb.

Se soubory se zachází jako s plnohodnotnou součástí. Nahrávání funguje na principu příslibu (promise): klient nahlásí, že chce nahrát soubor, dostane URL pro nahrání, pošle na ni data a v dalším volání se pak odkáže na dokončené nahrání. Tím se oddělí náročný přenos dat od zápisu záznamu, dobře to spolupracuje s cloudovými úložišti a endpointy API zůstávají rychlé. Stahování probíhá přes odkaz na záznam a řídí se stejným modelem oprávnění jako každé jiné čtení.

Zápis vnořených filtrů si zaslouží zvláštní zmínku, protože právě on uzavírá rozdíl ve vyjadřovacích schopnostech mezi rozhraním a API. Stejnou vnořenou strukturu AND/OR/poddotazů, jakou vytváří tvůrce dotazů, lze serializovat do řetězce dotazu, na serveru zpátky rozkódovat a použít bez zplošťování nebo přibližování. Integrace, která potřebuje "evropské zákazníky s fakturou po splatnosti, které nikdo nekontaktoval třicet dní", dokáže vyjádřit přesně tohle, aniž by musela slevit k jednoduššímu filtru.

Endpointy get-by najdou jeden záznam podle hodnoty jedinečné vlastnosti – hodí se, když znáte e-mailovou adresu, ale ne identifikátor, nebo když se vaše integrace opírá o obchodní identifikátor místo toho platformního. Rychlý dotaz GET /api/v1/collection/customers/get-by/email/... vrátí záznam bez toho, abyste museli nejdřív vypsat seznam a pak filtrovat.

Integrace potřebují, aby se souběh choval předvídatelně. API nabízí obvyklé postupy – optimistické aktualizace tam, kde dávají smysl, srozumitelné chybové kódy při konfliktech, idempotentní chování u patchů – a stránkování si tam, kde na tom záleží, rozumí s kurzorem. Platforma se nesnaží být databází; chce být důvěryhodným zdrojem pravdy pro konkrétní oblasti dat a API tomu odpovídá.

Autentizaci se podrobně věnuje článek o ochraně API. Webhooky – které celý obraz doplňují tím, že platforma umí aktualizace do integrací posílat sama, místo aby si je integrace musely tahat opakovaným dotazováním – mají také vlastní článek. Dohromady tato trojice, tedy REST API, ochrana a webhooky, umožňuje externím systémům používat platformu jako opravdový propojovací uzel. Řada našich zákazníků nad tímto API staví celé doprovodné aplikace – veřejné weby, mobilní aplikace, partnerské portály – zatímco samotná platforma poskytuje administrační rozhraní, datový model a pracovní postupy. Přesně pro tento případ jsme ho vytvořili.