GraphQL predstavlja posebno pripremljen jezik upita namijenjen za optimizirano slanje upita i dobivanje rezultata između klijenata i servera preko HTTP protokola. Za razvoj GraphQL-a “krivac” je Facebook koji prve implementacije jezika koristi u vlastitim mobilnim aplikacijama još od 2012 godine. Od 2015. godine tehnologija postaje javno dostupna svim zainteresiranim stranama, tako da se sve intenzivnije koristi u praksi i izvan okvira samog Facebooka.
Korištenje tehnologije GraphQL moguće je implementirati u različitim razvojnim alatima. U ovom tekstu ograničit ćemo se na primjer korištenja u programskom jeziku PHP, a kao izvor podataka koristit će se baza podataka MySQL.
PRIPREMA RAČUNALA
Pod pretpostavkom da na računalu već imate pravilno instaliranu i konfiguriranu bazu podataka MySQL i programski jezik PHP, za pisanje primjera u GraphQL-u potrebno je instalirati još nekoliko dodatnih modula. Naravno, i odgovarajuću MySQL bazu podataka kako bi se na njoj mogli izvoditi primjeri. Iako se testiranje primjera može izvoditi na različite načine, pretpostavit ćemo da u radu (kao većina korisnika) koristite preglednik Chrome te da ćete testiranje izvoditi upravo u njemu. U tom slučaju, prvo u Chrome treba instalirati odgovarajući dodatak ChromeiQL. Izravna web-adresa na kojoj je dostupan navedeni dodatak je:
https://chrome.google.com/webstore/detail/chromeiql/fkkiamalmpiidkljmicmjfbieiclmeij.
U slučaju da iz bilo kojeg razloga prethodnu vezu ne uspijete pravilno upisati/kopirati, možete upotrijebiti alternativni pristup – u trgovini dodataka za Chrome jednostavno napravite pretraživanje modula ChromeiQL. Provjera uspjeha instalacije dodatka je vrlo jednostavna. U gornjem desnom uglu preglednika treba se pojaviti novi gumb za njegovo pokretanje (označen je na pratećoj slici u nastavku).
Za implementaciju GraphQL upita u PHP jeziku koristit ćemo javno dostupnu biblioteku graphql-php, a nju možete pronaći na web-adresi:
https://github.com/webonyx/graphql-php
Biblioteku možete preuzeti klikom na gumb Clone or download ili korištenjem posebnog alata Composer, namijenjenog jednostavnijem preuzimanju sličnih dodataka u vlastite PHP projekte. U drugom slučaju treba koristiti naredbu:
composer require webonyx/graphql-php.
Slika 1. Dodatak ChromeiQL instaliran u preglednik Chrome
Opis demo baza podataka korištenih za demonstraciju GraphQL upita nastalih zajedničkim radom dvojice autora (Patrick Crews i Giuseppe Maxia) dostupan je na web‑adresi https://dev.mysql.com/doc/employee/en/employees-introduction.html.
Sama baza podataka u obliku spremnom za preuzimanje na vlastito računalo nalazi na adresi: https://github.com/datacharmer/test_db.
Slika 2. Pregled osnovnih tablica u demo bazi podataka
Po svojoj internoj strukturi baza je zapravo prilično jednostavna (sastoji se od svega šest tablica i dva pogleda), ali zato sadrži popriličan broj slogova u tablicama – ukupno oko 4 000 000 slogova. Sasvim dovoljan broj za korištenje u različitim primjerima poput optimizacije upita na bazu podataka i slično.
PRIMJER KORIŠTENJA U PHP-u
Prije prelaska na glavni dio primjera, zbog njegove cjelovitosti, navedimo sadržaj konfiguracijske datoteke config.php zadužene za nadzor pristupa bazi podataka:
<?php
$con = mysql_connect('localhost','root','') or die(mysql_error());
if (!$con) {
echo "Unable to connect to DB: " . mysql_error();
exit;
}
if (!mysql_select_db("employees")) {
echo "Unable to select mydbname: " . mysql_error();
exit;
}
mysql_query("SET NAMES 'utf8'");
mysql_query("COLLATE 'utf8_general_ci'");
?>
Po potrebi u prethodnoj datoteci izmijenite podatke o serveru, bazi i korisniku podacima s vlastitog računala.
Glavna datoteka sa samim programskim kodom primjera implementacije GraphQL jezika (datoteka graphql.php) sastoji se od nekoliko različitih dijelova. Izvođenje primjera pokreće se upisom sljedeće naredbe u prozoru za upis naredbi (“Naredbeni redak”):
php -S localhost:8080 ./graphql.php.
Preostalo je još samo da se u pregledniku Chrome, proširenom dodatkom ChromeiQL, pokrene taj dodatak te isproba primjer navođenjem odgovarajuće adrese u okviru Set endpoint:
http://localhost:8080
<?php
/* Dio 1 – uključivanje svih potrebnih modula */
require_once __DIR__ . './autoload.php';
require_once __DIR__ . "./_config.php";
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Schema;
use GraphQL\GraphQL;
try {
/* Dio 2 – postavljanje upita koji vraća rezultate */
$queryType = new ObjectType([
'name' => 'Query',
'fields' => [
'echo' => [
'type' => Type::string(),
'args' => [
'emp_no' => ['type' => Type::string()],
],
'resolve' => function ($root, $args) {
$query = "select s.salary, s.from_date, s.to_date, e.first_name,
e.last_name
from salaries s
inner join employees e on s.emp_no = e.emp_no
where s.emp_no = '" . $args['emp_no'] . "'
order by s.from_date desc limit 1";
$result = mysql_query($query);
while($rec = mysql_fetch_array($result)) {
$salary = $rec['salary'];
$period = $rec['from_date'] . ' - ' . $rec['to_date'];
$employee = $rec['first_name'] . ' ' . $rec['last_name'];
}
return $root['prefix'] . $salary . ' (' . $period . ') ' . $employee;
}
],
],
]);
/* Dio 3 – izvođenje mutacije */
$mutationType = new ObjectType([
'name' => 'Calc',
'fields' => [
'add' => [
'type' => Type::string(),
'args' => [
'emp' => ['type' => Type::string()],
'from' => ['type' => Type::string()],
'to' => ['type' => Type::string()],
'salary' => ['type' => Type::int()],
],
'resolve' => function ($root, $args) {
$query = "insert into salaries (emp_no, salary, from_date, to_date)
values ('" . $args['emp'] . "'," . $args['salary'] . ",'" .
$args['from'] . "','" . $args['to'] . "')";
$result = mysql_query($query);
if ($result == 1)
return "Added salary for " . $args['emp'];
else
return "Error adding salary";
},
],
],
]);
$schema = new Schema([
'query' => $queryType,
'mutation' => $mutationType,
]);
$rawInput = file_get_contents('php://input');
$input = json_decode($rawInput, true);
$query = $input['query'];
$variableValues = isset($input['variables']) ? $input['variables'] : null;
$rootValue = ['prefix' => 'Last salary: '];
$result = GraphQL::executeQuery($schema, $query, $rootValue, null, $variableValues);
$output = $result->toArray();
/* Dio 4 – obrada grešaka */
} catch (\Exception $e) {
$output = [
'error' => [
'message' => $e->getMessage()
]
];
}
/* Dio 5 – prikaz rezultata izvođenja */
header('Content-Type: application/json; charset=UTF-8');
echo json_encode($output);
U prvom dijelu, na samom početku datoteke izvodi se uključivanje svih potrebnih modula u programski kod. To je mjesto na kojem vlastiti PHP kod povezujemo s implemetacijom GraphQL jezika u programskom jeziku PHP – ranije spomenuta biblioteka graphql-php.
Drugi dio datoteke demonstrira implemetaciju GraphQL upita koji vraća podatke iz MySQL baze podataka. U konkretnom slučaju je to iznos zadnje plaće za zadanu šifru zaposlenika. Evo primjera GraphQL upita zadanog u pregledniku Chrome uz pomoć dodatka ChromeiQL:
query {
echo(emp_no:"10001")
}
Kao rezultat njegovog izvođenja dobije se:
{
“data“: {
“echo“: “Last salary: 88958 (2002-06-22 – 9999-01-01) Georgi Facello“
}
Osim čitanja postojećih podataka, GraphQL može se upotrijebiti i za dodavanje, izmjenu ili brisanje podataka u bazi podataka. U terminologiji GraphQL-a takav oblik naredbe naziva se “mutacija”.
Slika 3. Primjer izvođenja GraphQL upita u pregledniku Chrome
Evo primjera mutacije koja djelatniku sa šifrom 10001 dodaje novi iznos ukupne plaće za zadani period:
mutation {
add(emp: "10001", salary: 55555, from: "2017-01-01", to: "2018-01-01")
}
Nakon uspješnog dodavanja novog podatka u bazu, mutacija vraća poruku o uspjehu vlastitog izvođenja:
{
“data“: {
“add“: “Added salary for 10001“
}
Primijetite i da je u slučaju upita i u slučaju mutacije potrebno definirati sve dozvoljene argumente koje je potrebno poznavati za pravilno zadavanje upita. U prvom slučaju to je samo jedan parametar, emp_no, a u drugom slučaju četiri parametra: emp, salary, from i to.
Četvrti dio PHP datoteke zadužen je za obradu eventualnih pogrešaka nastalih prilikom izvođenja GraphQL upita. U praksi može biti bitno složeniji u odnosu na trenutačni primjer (kao uostalom i ostali dijelovi – na primjer, formatiranje datuma). Ne treba zaboraviti da greške prilikom izvođenja (posebno mutacija) mogu nastati i zato što sama MySQL baza ne dozvoljava njihovo izvođenje.
Na primjer, pretpostavimo da u tablici za zapis vrijednosti plaća definiramo UNIQUE indeks na stupcima za zapis šifre radnika te početnog i/ili završnog datuma na koji se odnosi vrijednost plaće. U tom slučaju ponovno izvođenje iste mutacije iz prethodnog primjera nije dozvoljeno, pa bi primjer vratio opis greške nastale prilikom izvođenja mutacije:
{
“data“: {
“add“: “Error adding salary“
}
Slika 4. Primjer izvođenja mutacije u pregledniku Chrome
ZAKLJUČAK
Jezik upita GraphQL predstavlja vrlo korisnu i danas široko rasprostranjenu tehnologiju za postavljanje različitih vrsta optimiziranih upita preko HTTP protokola. Osim implementacije u PHP jeziku, demonstrirane u ovom tekstu, uz pomoć odgovarajućih javno dostupnih biblioteka postoji mogućnost njegovog korištenja u većini najpopularnijih programskih jezika. Zato o njemu treba razmišljati kao o vrlo upotrebljivoj alternativi za druge tehnologije slične namjene.
Dodatne informacije o korištenju GraphQL jezika možete saznati na seminaru autora teksta koji bi se trebao održati u rujnu 2018. u prostorijama Srca.