Professional Documents
Culture Documents
Možda se odlučite za GraphQL kada budete radili neku od svojih budućih aplikacija nakon ovog
članka.
Uvod
Neke od tema koje će bit obrađivane u ovom poglavlju možemo sažeti u nekoliko pitanja,
a koja ćemo objasniti kasnije. Ta pitanja bi bila:
● Jeste li ikada čuli za termin GraphQL? Ako i jeste možda niste sigurni baš o čemu se tu
radi?
● Jeste li pomislili kako je GraphQL neka vrsta Graph baze podataka?
● Ako znate ponešto o GraphQL, mislite li da je on zamjena za REST?
● Ko i kako može koristiti GraphQL (misli se na programska okruženja i jezike)?
● Umorni ste od održavanja REST-a i stalnog ponavljanja jedinsvenih (unit) i funkcionalnih
testova?
Ako ste na bilo koje od ovih pitanja odgovorili sa DA, vjerovatno je ovaj članak za vas, u
suprotnom možete ići piti kahvu s voljenom osobom, igrati igrica ili raditi nešto treće.
Postoji popriličan broj zabluda oko GraphQL-a, pa ćemo u ovom članku pokušati da ih
predstavimo i po mogućnosti otklonimo. To je tako vjerovatno zato što je veoma malo dobrih
članaka koji GraphQL objašnjavaju od nule, za totalne početnike. Uglavnom se sve nešto
podrazumijeva ili se priča previše apstraktno. Ovdje će se pokušati približiti GraphQL svima,
kako apsolutnim početnicima tako i onima koji imaju odgovarajuće znanje i iskustvo.
Pa krenimo redom. GraphQL je jezik upita (query language) koji je izradio Facebook za
njihove potrebe još sada već, u ovom informatičkom svijetu može se reći, davne 2012. godine.
Zatim su oni odlučiti da to otvore za javnost 2015 u posebnoj speficikaciji
(https://facebook.github.io/graphql/draft/). Iz dana u dan Facebook mobilne aplikacije za Android
i iOS postajale su, i postaju sve složenije i složenije što dovodi do velikih problema, mnogih
grešaka (bugs), pa tako i padova samih aplikacija, što naravno ni jednoj kompaniji, a posebno
ne nekoj kao što je Facebook nije u interesu. Iz svega toga rodila se ideja da se razdvoje podaci
od grafičkog dijela. Također, s GraphQL se dobio i jedan novi pogled, jedno novo razmišljanje o
podacima koji dolaze kao resursi s URL-ova u grafikone objekata i modela koji se koriste u
krajnjoj aplikaciji. Više o ovim nekim detaljima može se naći na Facebook blogu
(https://code.fb.com/core-data/graphql-a-data-query-language/).
U REST-u, svaki entitet se jednostavno identifikuje pomoću resursa, koji je definisan
URL-om preko HTTP(S) protokola. Kada bilo ko traži podatke pomoću URL-a, zahtjev se tipično
rješava na web serveru koji autentifikuje zahtjev, preuzima podatke, obrađuje ih i vraća rezultat
klijentu. GraphQL je veoma, veoma sličan REST-u. Koristi se za dohvaćanje podataka iz bilo
kog pozadinskog servisa (Neka relaciona tabela, NoSQL, File system, ili čak i sam REST) koji
su tipizirani i koji također pružaju mogućnost Statelessness1 i Cacheability2. Međutim, razlika je
u načinu na koji se ovi podaci dobijaju. Pošto je GraphQL objavljen kao specifikacija, moguće je
implementirati GraphQL server na programskom jeziku po želji.
GraphQL je koristan protokol koji svakako treba znati, čak i ako je ovo prvi susret s
nekim od protokola. Što bismo rekli, to je budućnost, ali možemo reći i da je to sadašnjost i to
veoma zaustupljena i popularna. REST nije preduslov za razumijevanje GraphQL-a. Ako ste
ikada prije koristili REST uvidjećete prednosti GraphQL-a, ali ako niste, ne brinite.
1
Najjednostavnije objašnjenje je: Ne čuva se nikakva sesija na serveru tokom zahtjeva. To u
osnovi znači da server ne zna ništa o klijentu nakon što se upit završi.
2
Podrazumijeva da je moguće napraviti keš (ne, nisu pare u pitanju, ovdje se misli na prostor na
HDD ili RAM memoriji gdje pretraživač čuva kopije posjećenih veb stranica).
3
Vrijeme na koje se čeka od trenutka kada se pošalje zahtjev pa dok se ne dobije odgovor.
Veoma često se koristi kada se spominje satelitski internet, ili kada se govori o mobilnim
aplikacijama.
GraphQL ublažava probleme s pretjeranim ili nedovoljnim
unosom podataka
Zamislimo da izrađujemo mobilnu aplijaciju s kojom ćemo prikazivati fudbalske timove
svjetskog (ili trećeligaškog mahalskog, nebitno je) prvenstva grupisane po podjelama kako to
inače biva. Kada se prikaže lista timova, želi se preći na drugi prikaz s više detalja o timu,
položaju igrača i slično. Ovakva aplikacija se može bez problema napraviti uz pomoć REST-a i
imali bismo tu otprillike slijedeće URL-ove (koji su nadamo se samoopisujući):
GET api/teams
GET api/teams/1
GET api/teams/2
...
Ako se žele dohvatiti detalji za svakog pojedinačnog igrača, onda bi se trebala tražiti
lista, npr:
GET api/teams/1/roster
Zvuči jednostavno zar ne? Gdje je taj milioner koji je ovo riješio?
Ako je naša izgradnja platforme bazirana na REST API, onda bismo i eventualno web
stranicu koju imamo gradili na REST API. Naravno, pošto je to web stranica, tu je moguće
prikazati mnogo više podataka nego na tabletu, ili recimo mobitelu, a da i ne govorimo o nekom
pametnom satu. Sada bismo se vratili na naš REST i jednostavno dodali više podataka koji su
neophodni za web stranicu. Međutim, to znači da će mobilne aplikacije dobijati mnoštvo
beskorisnih podataka, a što će povećati latenciju, usporiti aplikaciju, povećati prenos podataka
preko mobilne mreže i slično. Nadalje kada se koristi REST API neizostavan je tzv N+1 problem
4
.
4
Ne postoji neka posebna definicija, ali može se opisati kroz primjer. Npr, zamislimo da pravimo
upit na bazu podataka da dobavimo sve automobile, zatim to vrtimo kroz neku petlju (for, while,
foreach) i za svaki korak petlje pravimo novi upit kako bismo dobavili još dodatnih podataka za
svaki pojedinačni automobil na osnovu trenutnog ID-a. Ovaj problem se naziva N+1 problem.
Da bi se riješio navedeni problem, može se jednostavno prije petlje pozvati novi upit na bazu i
tražiti da se vrati lista dodatnih podataka za listu ID-ova koje smo dobili iz liste automobila.
Menadžment Endpoint API-ja
Onima koji imaju iskustvo reći će kako je iznad spomenuti problem veoma jednostavno
riješiti tako što će se razdvojiti REST API za mobilne aplikacije i za web strancie. Da, to je istina!
Ali sada imamo najmanje duplo više API Endpoint-a, što usložnjava održavanje, unaprjeđenje,
testiranje, postavke sigurnosti i ostalo. Ovo je moguće riješiti na način tako da klijentska
aplikacija ustvari kaže koji joj podaci trebaju. Na taj način bi se izbjeglo dupliranje, tripliranje,
Endpoint API-ja. I tu na snagu stupa GraphQL s kojim se dobija samo jedan Endpoint za cijelu
aplikaciju. Zvuči čudno ili nemoguće? Ako vam je ovo do sada zagolicalo maštu, nastavite čitati.
Valja naglasiti također da GraphQL nije zamjena za REST. On se ustvari veoma dobro
uklapa u REST i može se koristiti za specifične slučajeve. U nastavku će biti više govora o
razlikama između REST-a i GraphQL-a, te kada je dobro koristiti jedan, a kada drugi.
Uvod u drugi dio
U nastavku kao uvod drugog dijela pokušaćemo predstaviti tabelu neku kao REST vs
GraphQL.
Server definiše oblik odgovora Klijent definiše kakav oblik odgovora želi da
dobije
5
Kao što je opšte poznato, semantika, kao riječ se koristi u mnogim oblastima, ali u računarstvu
je povezano s matematikom i odražava značenje nekog programa ili funkcije, odnosno definiše
značenje sintaksno ipravnih konstrukcija jezika.
Sintaksa u programiranju podrazumijeva pravilno korištenje ključnih riječi i logike programskog
jezika za pisanje funkcionalnog i logički ispravnog koda. Neki kod napisan sintaksno ispravno
(čitaj bez gramatičkih grešaka) ne znači i da je napisan semantički ispravno (čitaj logika mu je
taraba).
Razvrstavanje na stranice (Pagination) odvija Razvrstavanje na stranice se odvija unutar
se preko URL parametara GraphQL upitnih parametara
Ako se sjetimo onog N+1 problema iz prvog dijela ove priče može se zamisliti kako se
interakcije klijentskog servera dešavaju dok dohvatamo detalje fudbalskog tima koristeći se
REST endpointim-a, pa će se od servera dobiti nešto recimo nalik ovome:
{
"team":{
"id":"1",
"name":"FK Buducnost Banovici",
"division":"Crvendaci",
"owner":"RMK Banovici",
"headCoach":"Safet Susic",
"players":[
{
"__link":"api/teams/1/players/p1"
},
{
"__link":"api/teams/1/players/p2"
}
]
}
}
Pažljivim posmatranjem uočiće se da ovaj tim ima samo dva igrača (recesija, šta li) sa
pojedinačnim linkovima za dohvatiti detalje za svakog od njih, kako se ne bi lutalo ponovo
negdje po “index” strani da se dobavi lista igrača. To svakako smanjuje jedan korak, ali
svejedno da bi se dobili podaci za svakog igrača potrebno je poslati upit na svaki od navedenih
linkova (u ovom slučaju dva).
Ako bi se poslao upit ka serveru, server bi mogao vratiti nešto nalik ovome:
{
"player":{
"id":"p1",
"teamId":"1",
"name":"Semir Dedic",
"height":65,
"weight":175,
"position":"Strijelac"
}
}
Nakon ovih malih primjerčića može se bolje razumjeti onaj problem N+1 spomenut
naprijed. U ovom slučaju bi to značilo da ako se tim sastoji od N igrača data se valja poslati N+1
upita na server da bi se dobili svi neophodni podaci. Neko će reći kako se ovo sve može izbjeći i
dobiti rezultate svega u samo jednom upitu ka serveru. Ali sjetimo se šta smo pisali u prvom
dijelu ovog članka o količini podataka koje se traže i koje se dobijaju.
Ovi naprijed navedeni primjeri, odnosno upit ka serveru koji je pogodnjen GraphQL-om
bi imao slijedeći oblik:
query TeamDetails {
getTeam(id: "1") {
id
name
division
owner
headCoach
roster {
id
name
position
}
}
}
Da se primijetiti da je upit nekakva struktura, ali struktura koju definiše svaki pojedinačni
klijent za svoje vlastite potrebe. Ovaj upit se šalje recimo putem HTTP zahjeva, ali samo
jednom.
Komšijska trava je uvijek zelenija
U pozadini će se vjerovatno imati isti broj upita ka bazi podataka, ali će se smanjiti broj
upita na server preko HTTP endpointa. Neko će reći morebit, pa šta se dobilo onda? Skoro pa
ništa! Svakako, ako se prebaci sva logika na serversku stranu, onda će se napraviti i drugačiji
pristup ka bazi, obrada podataka i slično, što će na kraju davati bolji rezultat, a to i jeste poenta.
Postoje određeni izazovi koji valja biti svjestan prilikom upostavljanja i održavanja
GraphQL servera, a to su:
Za one koji koriste AWS neke stvari će biti umnogome olakšane jer AWS ima punu
podršku za GraphQL.
U GraphQL svijetu izrada aplikacija ide malko ili malo više drugačije. Server i klijent se
mogu izrađivati gotovo u potpunosti nezavisno ako su jasno definisane šeme sa tipovima koje
aplikacija zahtijeva/treba. Odnosi između tipova također trebaju biti definisani, a onda se pristupi
izradi upita tzv. mutacija za potrebe klijenta. Jednom kada se ovo jasno definiše, klijent šalje
svoj upit na GraphQL u potrazi za određenim setom podataka i naravno taj set, takav kakav
traži i dobija.
Ono što mnogi entuzijazisti zaborave često puta jeste struktura tima. Ko radi u frontend
timu, ko radi u backend timu? Da li su ljudi otvoreni ka novim idejama ili ne? Kakvo imaju
prethodno iskustvo i slično.
Napravite sebi neku kao listu (check list) koju trebate provjeriti prije nego se odlučite da
neki projekat migrirate na GraphQL. Slijedeća lista vam možda može pomoći kod donošenja
takvih odluka:
● Vaš trenutni proces je zamoran i postoji jako mnogo komunikacije između frontend i
backend timova.
● Uočavate probleme s performansama na REST endpointima zbog prevelikog ili
nedovoljnog preuzimanja podataka.
● Operativni troškovi na klijentu se stalno povećavaju, čak umnogostručuju zbog
složenosti podataka ili upravljanja postojećim REST endpointima.
Postoje barem tri pristupa/scenarija koje možete zamisliti kada se prelazi u svijet
GraphQL-a. Ovdje će se opisati ta tri scenarija.
Zakjučak
Ovaj članak je pr(ij)evod jednog članka objavljenog na engleskom jeziku s određenim
modifikacijama i prilagođavanjima. Autor članka se nada da je pristup GraphQL-u i REST-u u
ovom članku nepristrasan i da će pomoći kod odabira pravog rješenja za trenutnu ili aplikaciju
koju imate namjeru tek izrađivati. Kao što se da vidjeti, nema nikakvih konkretnih primjera u
6
Ubaci sve u jednu kapsulu koju je lakše progutati.
ovom članku, ali nadamo se daje jasan (ne tako precizan, ali nadamo se jasan) presjek šta je to
GraphQL, šta REST i koja je razlika između njih u praksi. Ako se odlučite za GraphQL i steknete
neka nova iskustva i znanja, podijelite sa svima nama, da i mi nešto naučimo.