GraphQL
GraphQL je specifikace dotazovacího jazyka pro tvorbu API. Existuje několik různých přístupů k tvorbě API, nejznámější konkurencí je však REST. Při porovnání právě s REST architekturou je jednou z velkých výhod to, že v GraphQL je potřeba specifikovat konkrétní data, která ze serverové části mají přijít na klientskou. Uživatel tak nedostává data, o která si explicitně neřekl, a tím se eliminuje přenos nepotřebných dat. GraphQL je silně typované. Pokud tedy chceme pracovat s nějakou entitou, musí být pro ni nadefinovaný typ. Pokud by byl zaslán požadavek na neznámý typ, volání skončí neúspěšně.
Vývojář | |
---|---|
První vydání | 2. července 2015 |
Operační systém | multiplatformní |
Licence | 3-clause BSD License |
Web | graphql |
Některá data mohou pocházet z datové položky. |
Vychází z matematické teorie grafů, kde se dle této teorie grafy skládají z vrcholů (nebo také uzlů) a hran. Pro GraphQL to pak prakticky znamená, že veškerá data musí být uspořádána do datových typů a každý tento typ v teorii grafů znázorňuje jeden vrchol. Hrany spojující tyto vrcholy pak vyjadřují vztahy mezi těmito datovými typy.
GraphQL bylo vytvořeno v roce 2012 společností Facebook za účelem zlepšení jejich mobilní aplikace. O tři roky později se objevuje jako open-source. V roce 2018 byla vydána poslední nejaktuálnější stabilní verze a na další se již pracuje (koncem roku 2020 byl vydán pre-release).
Rozdíl mezi GraphQL a REST
editovatTypickou charakteristikou pro REST je, že má mnoho endpointů. I pro jednodušší operaci je tedy často zapotřebí poslat na server hned několik požadavků (requestů), zatímco GraphQL má endpoint pouze jeden (typicky označován jako /graphql). Současně se vždy musí přesně definovat, o která data se žádá. Eliminuje se tak nejenom množství příchozích dat, ale i množství požadavků, které je potřeba na server odeslat. V GraphQL tedy neexistuje způsob, jak se obecně doptat na všechno, jako je typické například u dotazovacího jazyka SQL (př.: SELECT * FROM table;
). Pokud se chceme dotázat na vše, musíme explicitně vyjmenovat všechny atributy.
Mezi další významné rozdíly se řadí to, že GraphQL je nezávislé na protokolu. Oproti tomu REST je určen výhradně pro práci s daty pomocí metod odpovídajících HTTP protokolu. Z toho pak vyplývá i rozdílná práce s chybovými hláškami. Zatímco u REST architektury dostaneme v odpovědi příslušný HTTP status, na který lze následně reagovat, tak u GraphQL je přístup kvůli nezávislosti na protokolu odlišný. Nejpoužívanější přístup, který se objevuje i u většiny knihoven, obsahuje jen dva statusy. Těmi jsou status 400 pro chybný požadavek a status 200 pro vše ostatní. Pokud dojde k nějaké chybě, tak popis této chyby se následně objeví typicky v JSON odpovědi od serveru v části pojmenované „error“.
Schéma a typy
editovatV GraphQL jsou 3 základní objektové typy – Query, Mutation a Subscription. Tyto základní typy jsou tzv. entrypointy do GraphQL. Typ Query je povinný a je v něm definován seznam všech dotazů (queries), které je možné skrze GraphQL volat. Pokud by typ Query nebyl vůbec definovaný nebo by neměl definovanou alespoň jednu položku, tak API nedokáže vrátit žádná data, a je tak prakticky téměř nepoužitelné. Jak tedy částečně vyplývá z předchozí věty, typy se skládají z jednotlivých položek (fields).
Dále se dají definovat takzvané objektové custom typy. Těmi lze nadefinovat návratovou hodnotu jednotlivých položek (queries, mutations, subscriptions nebo položek jiných custom typů). Tyto custom typy jsou samozřejmě znovu použitelné, takže jejich vhodné nadefinování dokáže velmi zpřehlednit a zkrátit výsledný kód.
Návratovou hodnotou položky může být buďto některý z definovaných custom typů nebo některý ze základních typů tzv. skalární typ. Defaultními skalárními typy jsou pro GraphQL Int, Float, String, Boolean a ID (unikátní identifikátor reprezentovaný jako String). Speciálním skalárním typem je typ enumeration (enum), neboli výčtový typ. Stejně jako je možné definovat objektové custom typy, tak je možné definovat i skalární custom typy. Často používaným skalárním custom typem je například typ „Date“ pro datum. Návratová hodnota může být definována i jako pole skalárních či objektových typů. Návratové hodnoty lze ještě omezit tak, aby nebylo povoleno vracet hodnotu null. To se značí přidáním vykřičníku za danou návratovou hodnotu či pole hodnot.
Základem je pak takzvané schéma, což je kolekce všech objektových typů a jejich definic. Schématem se v podstatě definuje, jaká data mohou být posílána, přijímána a jaké jsou mezi nimi vazby. Na základě tohoto schématu je posléze možné vygenerovat dokumentaci, takže se o její tvorbu již není potřeba starat. Schéma je zpravidla definováno na jednom místě (např. pro JavaScript v souboru index.js). Pro rozsáhlejší aplikace může však schéma narůstat do obrovských rozměrů a stane se tak velmi nepřehledné. Existují proto nástroje, za pomoci kterých je možné schéma rozložit do více souborů.
Pro lepší představu jsou níže uvedeny dva ukázkové provázané custom typy (Author a Book) a k nim nadefinované jednoduché dotazy.
Příklad
editovatTyp Author
editovattype Author {
id: ID!
name: String!
birthYear: Int!
birthplace: String!
books: [Book!]!
}
Typ Book
editovattype Book {
id: ID!
name: String!
description: String!
releaseYear: Int!
isbn: String!
authors: [Author!]!
authorsIds: [ID!]!
}
Typ Query
editovattype Query {
books: [Book!]!
book(id: ID!): Book!
authors: [Author!]!
author(id: ID!): Author!
}
Resolvery
editovatResolvery jsou funkce v daném programovacím jazyce umožňující propojit schéma s cílovými daty. Je podporováno plno programovacích jazyků, mezi které patří například JavaScript, Java, C#, Python, PHP a další. Resolvery se dají rozdělit na dva typy. Prvním typem jsou resolvery pro základní objektové typy – Query, Mutation a Subscription. Tento typ slouží k tomu, aby tyto resolvery reálně vytáhly data, o která je žádáno, z cílového zdroje (databáze, soubory, další servery apod.). Druhým typem jsou resolvery pro objektové custom typy. Ve chvíli, kdy se specifikuje vztah mezi dvěma typy, musí se specifikovat i příslušný resolver.
V podstatě každá položka ze schématu musí mít svůj resolver, ne všechny je však potřeba definovat explicitně. Jednoduché resolvery dokáže většina GraphQL serverů vytvořit sama bez ruční definice. Na to se lze však spolehnout jen za předpokladu, že se atribut v objektovém typu jmenuje stejně, jako atribut, který přichází v objektu ze zdroje (opět z databáze, souborů apod.). Pokud se však jedná o resolvery, které s daty nějak dále pracují (například filtrace), je potřeba je definovat ručně.
Zjednodušeně by se tedy dalo říct, že schéma popisuje, jaká data jsou dispozici, zatímco resolvery pak s danými daty na základě příchozích queries, mutations a subscriptions už přímo nějak pracují.
Queries
editovatQueries neboli dotazy slouží pro získání dat. Z pohledu CRUD tedy zastupují písmeno R (read/retrieve) a z pohledu RESTu se dají přirovnat k metodě GET. Dotazy se skládají ze 4 částí. První částí je typ operace, což může být query, mutation nebo subscription. Druhou částí je pak název operace. Další dvě části už reprezentují dotaz na data, kde první z nich je název dotazu definovaného ve schématu a pak následuje výčet položek daného typu, na které se chceme dotázat.
query Authors {
authors {
name
birthYear
birthplace
}
}
Mezi výhody GraphQL patří i to, že nám umožňuje dotazy cyklit. Můžeme si to představit na jednoduchém příkladu již dříve definovaných knih a autorů. Každý autor může napsat více knih a každá kniha může mít více autorů. Mohli bychom například chtít vytvořit dotaz na základní informace o autorech včetně toho, jaké knihy napsali. U každé knihy by nás pak zajímaly informace i o konkrétní knize. Jednou ze základních informací je ovšem i to, jaké má autory (může jich mít více). Hodilo by se nám tedy dále i u knihy zjistit, kdo všechno se na její tvorbě podílel. V GraphQL se na tuto informaci můžeme jednoduše dotázat jedním dotazem.
query AuthorsAndBooks {
authors {
name
birthYear
books {
name
description
authors {
name
}
}
}
}
Mutations
editovatMutations neboli mutace zastupují zbylé operace z pohledu CRUD, tedy přidávání, aktualizování a mazání. Zatímco dotazy data pouze načítají, mutations s daty manipulují. Z pohledu RESTu tedy zastupují metody PUT, POST a DELETE.
Subscriptions
editovatTřetím typem operace je takzvaný subscription, který podobně jako dotazy čte data. V porovnání s dotazy se však jedná o aktivní spojení se serverem a tím pádem nám poskytuje vždy aktuální data (tzv. real-time data). To je vhodné například pro zasílání notifikací nebo pro tvorbu chatovacích aplikací.
Externí odkazy
editovat- (anglicky) Oficiální stánky
- (anglicky) Queries and Mutations
- (anglicky) Schemas and Types
- (anglicky) Apollo implementace GraphQL
- (anglicky) Subscriptions
- (anglicky) Resolvery
- (anglicky) Rozložení schématu do více souborů Archivováno 5. 12. 2020 na Wayback Machine.
- (anglicky) QraphQL specifikace