Elektrotehniški vestnik 86(1-2): 43-46, 2019 Izvirni znanstveni članek Spletne storitve z GraphQL Domen Kajdič, MatjaZ B. Jurič Univerza v Ljubljani, Fakulteta za računalništvo in informatiko, Večna pot 113, 1000 Ljubljana, Slovenija E-pošta: domen@kajdič.net, matjaz.jurič@fri.uni-lj.si Povzetek. Spletne storitve so ključnega pomena za razvoj sodobnih aplikacij. Omogočajo komunikacijo čelnega in zalednega dela aplikacij. Ceprav se nove tehnologije pojavljajo dokaj pogosto, se razvijalci aplikacij pogosto oklepajo starejših tehnologij zaradi njihove dozorelosti in široke podpore. Najpogosteje uporabljeni tehnologiji za komunikacijo sta REST in SOAP, ki pa se nista spremenili ze vec let. V clanku bomo predstavili tehnologijo GraphQL, ki je bila razvita kot odgovor na pomanjkljivosti trenutnih nacinov komunikacije. Tehnologijo bomo primerjali s storitvami REST kot glavno alternativo in pokazali, na kakšen nacin odpravlja njene pomanjkljivosti. Na koncu se bomo dotaknili arhitekture mikrostoritev, ki predstavlja sodoben nacšin razvoja aplikacij, ter predstavili uporabo GraphQL in arhitekture mikrostoritev v tandemu. Ključne besede: tehnologija GraphQL, spletne storitve, arhitektura REST, razvoj sobodnih aplikacij Web services with GraphQL Web services are of key importance when it comes to developing modern applications. They allow communication of the front- and back-end. Though new technologies are often developed, developers often choose to stick with the old ones for being more mature and providing more support and documentation. The most widely-used communication technologies today are REST and SOAP which have not changed in the past couple of years. In this paper, the GraphQL technology is presented as an answer to shortcomings of the current technologies. It is compared to REST as its main alternative. At the end, microservices are introduced as a modern way of developing applications. The concept of microservices is used as an efficient way of showing how the GraphQL technology can be used in a modern environment. Keywords: GraphQL technology, web services, REST architecture, modern applications 1 Uvod in definicije GraphQL je poizvedovalni jezik, ki omogoča preprosto pridobivanje podatkov iz zalednega dela aplikacije. Razvilo ga je podjetje Facebook, in sicer predvsem za interno uporabo. Leta 2015 so ga prvic predstavili javnosti skupaj z objavo specifikacije [11] in referencne implementacije v programskem jeziku JavaScript [5]. Zdaj je na voljo v vecini popularnejsih programskih jezikov [6], vendar je sele v zadnjem letu zacel pridobivati na popularnosti. Kot primer uporabe lahko omenimo podjetje GitHub, ki je novo verzijo svojega apija izdalo s pomocjo GraphQL [8]. Ime GraphQL izvira iz dveh delov: Graph oznacuje graf; kratica QL pomeni query language oz. po slovensko poizvedovalni jezik. Pri GraphQLu si torej pridobi- Prejet 30. oktober, 2018 Odobren 17. december, 2018 vanje podatkov lahko predstavljamo kot premikanje po grafu. Klasicen graf definiramo kot mnozico vozlišc in povezav: G =(V,E) (1) pri cemer je V mnozica vozšlišc (vertices) in E mnozica povezav (edges) [9] [10]. Za lazje razumevanje bomo predstavljeno ilustrirali na grafu na sliki 1. Na ta primer se bomo sklicevali skozi ves clanek. Slika 1: Primer grafa Na grafu na sliki 1 opazimo štiri entitete: študente, predmete, predavalnice in predavatelje. To so vozlišca grafa, ki jih oznacšimo s krogi. Vsaka izmed entitet ima neke lastnosti (npr. sštudent ima definirano ime), ki pa jih zaradi berljivosti nismo dodali na sliko. Student obiskuje predmete, vsak predmet je predavan v neki predavalnici in ima nekega predavatelja. To so povezave grafa, ki jih oznacšimo s pusšcšicami. Povezave so lahko enosmerne ali dvosmerne. Dvosmerno povezavo med vozlišcema A in B definiramo kot povezavo od A do B in hkrati povezavo od B do A. Kot smo prej omenili, pridobivanje podatkov poteka s premikanjem po grafu. Poizvedbo dobimo tako, da si izberemo neko tocko in se zacnemo premikati po njenih izhodnih povezavah. 44 KAJDIC, JURIC Primeri poizvedb: • Vrni ime in priimek vseh študentov, ki obiskujejo predmet 1. • Vrni vpisne številke študentov, ki obiskujejo predmete pod mentorstvom predavatelja 1. • Vrni vsa imena predmetov, ki jih predavata predavatelja 1 in 2. 2 Kako deluje GraphQL V tem odseku bomo zgoraj predstavljeno logiko in poizvedbe pretvorili v notacijo GraphQL. Predstavili bomo tudi sintakso jezika in primer poizvedbe. GraphQL lahko grobo razdelimo na tri dele: poizvedovanje, definiranje sheme in izvajalno okolje. Vsakega izmed treh bomo na kratko predstavili. 2.1 Poizvedovanje Poizvedovanje je glavni razlog, zakaj se razvijalec odloČi za uporabo GraphQL. Pred opisom poizvedovanja bomo pokazali, kako izgleda prava poizvedba na streznik GraphQL. // poizvedba query { vrniPredmet(id: "1") { študenti { ime priimek } } } // rezultat poizvedbe { "vrniPredmet": { "študenti": [ { "ime": "Janez", "priimek": "Novak" } ] } } Cš e pogledamo zgornjo poizvedbo, opazimo naslednje lastnosti: • Sintaksa poizvedovanja je izpeljana iz formata JSON [4]. • Izbirnost podatkov: uporabnik si lahko izbira, katera polja naj mu streznik vrne. • Sš tevilo poizvedb: ena poizvedba je ponavadi dovolj za pridobitev vseh potrebnih podatkov. • Rezultat poizvedbe: rezultat je enake oblike kot zahteva; uporabnik točno ve, v kakšni obliki bo streznik vrnil podatke. 2.2 Definiranje sheme Da bi bilo poizvedovanje mogocše, je treba definirati shemo. V shemi je treba definirati vse podatkovne tipe, ki jih bomo uporabljali pri poizvedovanju (v našem primeru so to prej omenjene štiri entitete), kot tudi vse operacije, kijih uporabnik lahko uporablja v poizvedbah. Ce pogledamo na prejšnji graf, operacije so točke na grafu, na katerih lahko vstopimo v graf (podmnozica tock). GraphQL podpira naslednje skalarne tipe: celo sštevilo (Int), decimalno število (float), niz znakov (String), logicšni izraz (Boolean) in enolicšni identifikator (ID; obravnavan kot niz znakov). Poleg tega so podprti še seznami (oznacšimo z []), vmesniki (Interface), unije (Union) in naštevni tipi (Enum). Vsi uporabniško definirani tipi morajo biti sestavljeni iz osnovnih skalarnih tipov ali kaksšnih drugih uporabnisško definiranih tipov. Definirati je treba tudi operacije. GraphQL podpira tri vrste operacij: bralne operacije (query), pisalne operacije (mutation) in narocnine (subscription) [3]. Bralna operacija je namenjena standardnim poizvedbam za pridobivanje podatkov, pisalne operacije so namenjene spreminjanju podatkov in narocnine so namenjene konstantnemu spremljanju neke vrednosti (npr. cene delnic). Ce pogledamo zgornjo poizvedbo, imamo podatkovni tip sštudent, ki vsebuje vsaj polji ime in priimek; podatkovni tip predmet, ki vsebuje enolicni identifikator predmeta (id), in seznam študentov ter bralno operacijo vrniPredmet, ki zahtevani predmet vrne. Shema bi v notaciji GraphQL izgledala tako: type Student { ime: String priimek: String // ostala polja } type Predmet { id: ID! študenti: [Student] // ostala polja } type Query { vrniPredmet(id: ID!): Predmet // ostale operacije } // ostali tipi in operacije 2.3 Izvajalno okolje Zadnja komponenta GraphQL je izvajalno okolje. To je zaledje GraphQL oz. drugace povedano program, ki sprejema, procesira in vraca poizvedbe (ki so bile prej definirane v shemi). GraphQL je neodvisen od transportnega protokola (transportno agnosticšen), kar pomeni, da ga lahko uporabljamo prek poljubnega transportnega protokola (v vecini primerov je uporabljen protokol SPLETNE STORITVE Z GRAPHQL 45 HTTP) [1]. Celotna logika pridobivanja podatkov temelji na t. i. razresevalskih funkcijah (resolver functions). Vsaka operacija in vsako polje v podatkovni shemi vsebuje svojo razresevalsko funkcijo, ki jih izvajalno okolje ob prejetju poizvedbe poklice v določenem vrstnem redu. Razresevalske funkcije mora napisati razvijalec. Da bi res razumeli, kaj se dogaja ob prejetju poizvedbe, bomo ilustrirali celotno dogajanje ob prejetju prej omenjene poizvedbe z operacijo vrniPredmet [13]. 1) Uporabnik poslje poizvedbo na streznik GraphQL prek izbranega transportnega protokola. 2) Izvajalno okolje sprejme poizvedbo, jo najprej sin-takticsno preveri (pogleda format poizvedbe in preveri, ali v shemi obstaja operacija vrniPredmet). Ce obstaja, poklice njeno razresevalsko funkcijo, ki vrne dolocseni predmet. Cs e preverba ne uspe, vrne uporabniku napako. 3) Izvajalno okolje pogleda v shemo, kakssna polja vsebuje entiteta predmet in kaksne polja je zahteval uporabnik. V nasem primeru je zahtevano le eno polje, in sicer polje studenti (ki je tipa seznam sstudentov). 4) Izvajalno okolje poklice razresevalsko funkcijo polja studenti, ki vrne vse sstudente. 5) Izvajalno okolje pogleda v shemo, kaksna polja vsebuje entiteta Študent in kaksna polja je zahteval uporabnik. V nassem primeru sta zahtevani polji ime in priimek. 6) Izvajalno okolje za vsakega študenta poklice ra-zressevalski funkciji za pridobivanje imena in priimka. 7) Pridobljeni podatki se sestavijo v koncni rezultat in vrnejo uporabniku (ponavadi v formatu JSON). 3 Primerjava GraphQL z arhitekturo REST Vecsina sodobnih aplikacij za komunikacijo med cselnim in zalednim delom uporablja arhitekturo REST. Kljub razsirjeni uporabi ima arhitektura REST stevilne pomanjkljivosti [14]. GraphQL je bil zasnovan kot odgovor na te pomanjkljivosti: • Pri arhitekturi REST se entitete nahajajo na svojem naslovu. Ce to preslikamo na nas primer, bi imeli stiri dostopne tocke: /student, /profesor, /predmet in /predavalnica. Uporabnik, ki bi hotel delati zah-tevnejse poizvedbe, bi moral v najslabsem primeru narediti sstiri poizvedbe. Pri kakssnih kompleksnejssih aplikacijah se ta sstevilka lahko zelo povecsa. Ne glede na sstevilo entitet se z uporabo GraphQL stevilo zahtev zmanjsa na eno samo. • Pri arhitekturi REST se lahko zgodi, da mora neka aplikacija hraniti vecs vzporednih dostopnih tocsk, saj nekatere aplikacije se niso bile posodobljene na nove verzije. To pomeni, da ima lahko aplikacija za neko entiteto vec dostopnih tock: starejsa verzija /v1/student in verzija /v2/student z novimi funkcinalnostmi. Pri GraphQLu se lahko temu izognemo, saj je dodajanje in spreminjanje polj v podatkovnih tipih preprosto in neodvisno od njihove implementacije (polje dodamo v shemo in dodamo razresevalsko funkcijo). Dodana polja ne morejo uničiti nobene poizvedbe. Razresevalske funkcije lahko v celoti spremenimo in koncni uporabnik tega ne bo opazil, saj bo delal enake poizvedbe, kot jih je delal prej. • S tem ko uporabnik pri poizvedovanju sam izbira, katere podatke hoce pridobiti, se mocno zmanjša kolicina prenesenih podatkov. Pri arhitekturi REST dostopne tocke ponavadi vracajo celotne entitete z vsemi polji, ki pa jih aplikacija ponavadi ne potrebuje. To je bila ena izmed motivacij podjetja Facebook pri razvoju GraphQL, saj je prenos podatkov v nerazvitih predelih sveta velik problem. • GraphQL omogoca t. i. introspekcijo [7]. Vsak streznik omogoca poizvedovanje po operacijah in podatkovnih tipih, ki so na voljo. Lahko sestavimo poizvedbo, ki vrne mogoce operacije za naslednje poizvedbe. Pri arhitekturi REST mora za to poskrbeti razvijalec z uporabo razlicnih orodij (najpopularnejšo je orodje Swagger) ali kakšnih drugih pristopov. Kljub temu tehnologija GraphQL ne more popolnoma zamenjati alternativ [15]. V nekaterih primerih lahko uporaba GraphQL prinese celo negativne posledice: • Pri zelo preprostih podatkih oz. podatkih z malo relacijami lahko uvedba GraphQL poizvedovanje upocšasni. Tipicšen primer so aplikacije interneta stvari, ki zbirajo senzorske podatke z vnaprej doloceno obliko. Poizvedba REST bo hitrejša, saj procesiranje in tudi definiranje sheme (ki bi bila trivialna) v tem primeru ne bosta potrebna. • Pri uporabi GraphQL je lahko zaradi izbirnosti vsak izhod poizvedbe drugacen. Zato je otezeno predpomnjenje rezultatov poizvedb. V arhitekturi REST je izhod vedno iste oblike. • GraphQL je relativno nova tehnologija, kar se pokaze predvsem v manjšem številu orodij in dokumentacije. Ce gre kaj narobe, bomo z uporabo alternativ lazšje nasšli resšitve kot pri uporabi GraphQL. 4 GraphQL in mikrostoritve Pod pojmom mikrostoritve oznacujemo sodoben nacin razvoja aplikacij, pri cemer aplikacije razdelimo na manjše komponente - mikrostoritve [2]. Pri tem poskušamo doseci cim vecjo neodvisnost med posameznimi mikrostoritvami. Pri razvoju se nagibamo k cim vecji preprostosti posameznih mikrostoritev: vsaka mi-krostoritev opravlja neko doloceno funkcijo. Komunikacija poteka izkljucšno prek predefiniranih vmesnikov (REST, cakalne vrste, ad - hoc pristopi...). Ta lastnost se imenuje šibka sklopljenost. Posledicno lahko za vsako posamezno mikrostoritev skrbi druga razvijalska ekipa 46 KAJDIC, JURIC z drugim razvojnim ciklom. Se vec: vsaka mikrostori-tev je lahko napisana v svojem programskem jeziku. Glavna prednost uporabe mikrostoritev je predvsem učinkovitejše skaliranje aplikacij. Aplikacijo lahko ska-liramo glede na najbolj uporabljane funkcionalnosti oz. skaliramo samo tiste mikrostoritve, ki morajo obdelati najvec prometa. Primer takšnega skaliranja je skaliranje mikrostoritve katalog izdelkov v neki spletni trgovini. Skaliranje, pri katerem skaliramo le posamezni del aplikacije z zagonom vec instanc te aplikacije, imenujemo horizontalno skaliranje. Nasprotje horizontalnega skaliranja je vertikalno skaliranje, pri katerem pa skaliramo celo aplikacijo s povecanjem strezniških zmogljivosti (vec RAM, hitrejši CPU...). Aplikacija, ki sledi konceptom mikrostoritev, je sestavljena iz velikega števila mikrostoritev. Ce se postavimo na stran razvijalca zalednega dela aplikacije, opazimo problem. Da bo aplikacija pridobila zahtevane podatke, bo morala narediti veliko zahtev na posamezne mikro-storitve. Pride ravno do problema, ki smo ga omenjali prej. Ta problem lahko rešimo ravno z uvedbo GraphQL. Na prvi pogled imamo dva nacšina uvedbe: uvedba na posameznih mikrostoritvah ali ustvarjanje nove mikro-storitve, ki bo agregirala vecš mikrostoritev. Drugi nacšin je veliko boljši od prvega, saj s tem zdruzimo celotno aplikacijsko shemo v eno mikrostoritev. Ustvarimo novo dostopno tocko, ki omogoca pridobitev poljubnih podatkov iz celotne aplikacije z mocšjo poizvedovanja GraphQL. Razreševalske funkcije uporabimo kot nacin pridobivanja podatkov iz preostalih mikrostoritev. Ce bi uvajali GraphQL na posameznih mikrostoritvah, bi s tem aplikacijo naredili kompleksnejšo. V arhitekturi mikrostoritev je komunikacija med posameznimi mikro-storitvami kljucšnega pomena. GraphQL bi to komunikacijo upocasnil, saj je pošiljanje poizvedb GraphQL kompleksnejše od pošiljanja poizvedb REST. 5 Sklep V cšlanku smo predstavili GraphQL, ki je ena od novejsših tehnologij za komunikacijo cšelnega dela z zalednim. Primerjali smo ga z arhitekturo REST ter predstavili njegove prednosti in slabosti. Na koncu smo se dotaknili tudi arhitekture mikrostoritev, ki je eden od sodobnejsših nacinov razvoja spletnih aplikacij. Pokazali smo, kako se lahko GraphQL ucšinkovito uporabi v arhitekturi mi-krostoritev. Glavni cilj pisanja tega cšlanka je bila seznanitev bralca s sodobnimi koncepti spletnih storitev in razvoja aplikacij. Posledicno smo v clanku nanizali veliko novih pojmov in konceptov, ki jih neizobrazšeni bralec na tem podrocju ne bo poznal oz. bodo zanj novi. Zainteresirani bralec se lahko podrobneje seznani s tematiko z branjem diplomskega dela z naslovom "Spletne storitve z GraphQL", ki je javno dostopno na spletni strani Fakultete za racunalništvo in informatiko [12]. V diplomskem delu se veliko bolj poglobimo v specifike GraphQL in arhitekturo mikrostoritev. Velik del je namenjen tudi programiranju mikrostoritev GraphQL v programskem jeziku Java. Literatura [1] E. Porcello, A. Banks, Learning GraphQL: Declarative Data Fetching for Modern Web Apps, O'Reilly Media, 2018. [2] M.Richards, Microservices AntiPatterns and Pitfalls, O'Reilly Media, 2016. [3] GraphQL: Schemas and Types, dosegljivo: https://graphql.github.io/learn/schema/, 2018. Dostopano: 22. 10. 2018. [4] GraphQL: Best Practices, dosegljivo: https://graphql.org/learn/best-practices/, 2018. Dostopano: 22. 10. 2018. [5] GraphQL.js, dosegljivo: https://github.com/graphql/graphql-js, 2018. Dostopano: 22. 10. 2018. [6] GraphQL libraries, dosegljivo: https://graphql.github.io/code/, 2018. Dostopano: 22. 10. 2018. [7] GraphQL Introspection, dosegljivo: https://graphql.org/learn/introspection/, 2018. Dostopano: 22. 10. 2018. [8] GitHub GraphQL API v4, dosegljivo: https://developer.github.com/v4/guides/intro-to-graphql/, 2018. Dostopano: 22. 10. 2018. [9] Teorija grafov, dosegljivo: https://sl.wikipedia.org/wiki/Teorija_grafov, 2018. Dostopano: 22. 10. 2018. [10] Teorija grafov, dosegljivo: http://www.educa.fmf.uni-lj.si/izodel/sola/2006/ura/oblak/html/Uvod.html, 2006. Dostopano: 22. 10. 2018. [11] GraphQL specification, dosegljivo: https://facebook.github.io/graphql/draft/, 2018. Dostopano: 22. 10. 2018. [12] D. Kajdic, Spletne storitve z GraphQL: diplomsko delo, dosegljivo: http://eprints.fri.uni-lj.si/4231/ , 2018. Dostopano: 15. 10. 2018. [13] GraphQL explained, dosegljivo: https://dev-blog.apollodata.com/graphql-explained-5844742f195e, 2016. Dostopano: 22. 10. 2018. [14] GraphQL vs. REST, dosegljivo: https://dev-blog.apollodata.com/graphql-vs-rest-5d425123e34b, 2017. Dostopano: 22. 10. 2018. [15] Pain Points of GraphQL, dosegljivo: https://labs.getninjas.com.br/pain-points-of-graphql-7e83ba5ddef7, 2017. Dostopano: 22. 10. 2018. Domen Kajdic je magistrski študent Fakultete za racunalništvo in informatiko. Diplomiral je leta 2018 pod mentorstvom prof. dr. Matjaza Branka Junca na temo GraphQL. Prof. dr. Matjaž B. Jurič, redni profesor, avtor 18 knjig, izdanih pri mednarodnih zaloZbah, ter vec kot 600 drugih publikacij. Prejel je vec mednarodnih nagrad, med drugim nagrado za najboljšo SOA knjigo (New York), nagrado za najboljši SOA projekt v telekomunikacijah (Las Vegas), nagrado Java Duke's Choice Award Winner (San Francisco) za najboljsšo inovacijo v Javi, naziv java champion, nagrado za najboljsši znanstveni cšlanek s podrocšja storitev, nagrado za najboljsšega raziskovalca po mnenju industrije in zlato plaketo za izjemne zasluge pri razvijanju znanstvenega ustvarjanja.