2021. április 18., vasárnap

Gyorskeresés

Easybackend PHP-vel és Fetch API frontendel

Írta: | Kulcsszavak: PHP . backend . JavaScript . frontend . Fetch . API . GitHub . Heroku . Webfejlesztés

[ ÚJ BEJEGYZÉS ]

A backendet legtöbbször arra használunk, hogy adatokat küldjünk neki és az letárolja ezeket a kapott adatokat, majd visszaküldje azt a frontendnek, ha annak szüksége van rá. Magyarul úgy is mondhatjuk, hogy háttérrendszer. De akár számításokat is lehet elvégeztetni egy ilyen háttérrendszerrel, nemcsak tárolásra alkalmas.
A cikkben bemutatott kódok egyikében sincsenek adatbázis kapcsolatok, nincsenek benne bonyolult dolgok, épp ezért szeretném az alább bemutatott kis "Easybackend"-en illetve az ehhez kapcsolódó "Easyfrontend"-en keresztül bemutatni neked a Backend vs Frontend kommunikáció működését, ha kezdő vagy és nem nagyon érted miről van szó.

Mit csinál a bemutató alkalmazás? Az alkalmazás bekér egy számot, amit továbbít a szervernek, az megkapja ezt a számadatot, majd nagyon egyszerű műveleteket hajt végre rajta (Duplázás, Felezés, Hozzáad egyet, Levon belőle egyet stb), ezután a frontend lekéri a kiszámolt végeredményeket és kiírja egy megadott "div"-be (Lásd HTML alapismeretek).

Backend
Nézzük először a backendet. Tudom, hogy kezdő webfejlesztőként ez sokkal riasztóbb, mint a frontend JavaScript, vagy a HTML-el vagy a CSS-el való babrálás, de ebben az esetben ez a legrövidebb kód és talán a legjobban emészthető a működése.
A backendnek szerver oldali scriptnyelveket szoktunk választani, de nem csak a Node.js létezik erre a célra, hanem még a nagyon régi, mondhatni "történelmi" múltra visszatekintő PHP is alkalmas a feladatra. Szinte bármelyik ingyenes hostingnál adnak PHP kiszolgálót, épp ezért egy nagyon hozzáférhető cucc a Node.js-el szemben, amihez a legtöbb esetben jobb, ha saját szervert futtat az ember, vagy VPS-t (azaz virtuális szervert). Épp ezért választottam és is a PHP nyelvet ehhez a kis EasyFrontend-hez.
A backendünk egyetlen .php kiterjesztésű fájl lesz, a neve bármi lehet, amit FTP vagy SFTP segítségével tudunk feljuttatni a PHP-t futtató szerverünkre vagy a Herokura, ami egy konténer-alapú felhőplatform szolgáltatás, ebbe a Github-ról is tölthetünk fel közvetlenül kódokat.

A backend kódja a következő:

<?php
// Frontend script for this backend
// https://codepen.io/bzozoo/pen/yLVoQxo?editors=0010

header("Access-Control-Allow-Origin: *");
header('Content-Type: application/json');

if(isset($_POST['kapottadat']) && is_numeric($_POST['kapottadat'])){

$kapottSzamAdat = $_POST['kapottadat'];
$data = Array(
'Dupla' => $kapottSzamAdat * 2,
'Felez' => $kapottSzamAdat / 2,
'Hozzaad' => $kapottSzamAdat + 1,
'Levon' => $kapottSzamAdat -1,
'Hello' => "Hello " . $kapottSzamAdat . "!",
'Visszakap' => $kapottSzamAdat,
'Error' => false
);

echo json_encode($data, JSON_PRETTY_PRINT);
} else {
$data = Array(
'Error' => true
);
echo json_encode($data, JSON_PRETTY_PRINT);
}

Nézzük mit csinál a kód.
Minden PHP kódot <?php tag-el kezdünk (persze vannak más módok is).
Nyitnunk kell headereket. A header("Access-Control-Allow-Origin: *") beállítás arra szolgál, hogy a PHP backendünket bármilyen frontend elérje, ne csak az adott domainről lehessen lekérni.
A header('Content-Type: application/json'); előre jelezheted, hogy milyen dokumentum tartalom típust szándékozol kiszolgálni. Erről bővebben a PHP.net-en olvashatsz.
Ezután a JavaScript esetén is már jól ismert IF statement következik.
$_POST['kapottadat'] egy speciális változó. Mindig azt az értéket tartalmazza, amit a HTTP fejlécben POST metódussal megkap a hozzátartozó kulccsal (Ami az esetünkben a 'kapottadat') egy formtól vagy akár Fetch API-val egy JavaScript frontendtől. (A frontenden én ez utóbbit fogom használni)
Isset: Ez megmutatja, hogy létezik e a változó. Ha igen, az értéke true. is_numeric: Ez ellenőrzi, hogy a változó szám e. Ha igen, az értéke true.
Ebből következik, hogy az if(isset($_POST['kapottadat']) && is_numeric($_POST['kapottadat'])) azt jelenti, hogy a programkódunk akkor tegyen valamit, ha létezik az $_POST['kapottadat'] speciális változó és az számot tartalmaz.
Ha az if statement értéke mind igaz, akkor egy $data tömböt hozunk létre. Ezekre (if statement, array és társai) emlékezhettek a legtöbbetek által ismert JavaScript nyelvből is.
A PHP-ben a tömb kulcsot és a tömb értéket => -el válasszuk el.
A $_POST['kapottadat'] értékét beletesszük egy $kapottSzamAdat nevű változóba, majd a $data tömb értékeinél elvégezzük a számításokat. A tömb kulcsneveit pedig a számításnak megfelelően adjuk meg, hogy a későbbiekben könnyedén felismerjük, illetve a frontenden is ezzel fogunk dolgozni. Tudjuk ugyebár, hogy a tömbkulcs lehetne akár 0 1 2 ...stb is, de nevesítve könnyebb a megjegyzés.
Ezután az echo json_encode($data, JSON_PRETTY_PRINT); sorral en-kódoljuk a data tömböt, majd kiíratjuk a képernyőre. Nézz utána az echo-nak és a json_encode-nak a PHP.net-en, ha még nem hallottál róla.
Ha az if feltétel nem teljesül, akkor a data tömb az error kulcs mellé egy true értéket kap. Ez fontos lesz a frontendnek küldött válasz során.

Tehát akkor foglaljuk össze néhány mondatban, még egyszer, hogy mit csinál ez a backend.
Vár egy POST értéket egy formtól, ami egy szám érték. Ha ezt megkapja, a kapott értéken műveleteket hajt végre egy tömb érékeként, majd ezt JSON formátumban jeleníti meg. Ha nem kap, akkor egy Error => true kulcs - érték párt jelenít meg, ugyancsak JSON formátumban. Ami mint tudjuk, univerzális adatátviteli lehetőségként szolgál különböző platformok között. Mint például a következőkben bemutatott JavaScript frontend és az előbbiekben bemutatott PHP backend között.

Frontend
A frontend, az a felület, amivel a felhasználó találkozik. Ez a felület képes kommunikálni a backend-el, adatot küldeni neki, adatot fogadni, azt kiírni a megfelelő helyre, ami rendszerint egy HTML div.
Mivel tudunk adatot bevinni? Természetesen van több módszer is, de szerintem egy input mező erre a legalkalmasabb. Mivel tudunk adatot küldeni és lekérni? Erre is van több módszer, én a Fetch API-t fogom használni.

A HTML KÓD

<div id="description">
Küldj el egy számot a backend szervernek, ami elvégez néhány számítást, majd visszaküldi az eredményt.
</div>
<div id="input">
<input type="number" name="numberInput" id="numberInput" value="1000" placeholder="1000">
<input type="submit" id="submitNumber" name="submitNumber">
</div>
<div id="data">
</div>

A felhasználói felület kódja így néz ki. Remélem ehhez már kezdő webfejlesztőként sem kell túl sokat hozzáfűzni. Van benne egy input mező, egy küldő gomb, alatta pedig a data div. Az a rész, ahova a szervertől visszakapott adatokat írhatjuk.

A JAVASRIPT KÓD
A JavaScript kód, ami a munkát végzi. Ez az ami interaktívvá teszi a kódunkat. Ezt több részletben fogom bemutatni.

let dataDiv = document.querySelector("#data")
let submitButton = document.querySelector("#submitNumber")
let backendUrl = "https://scriptteszt.mysqhost.tk/php/easybackend/"

Elsőként mindig a program változóit szoktam felvenni. Változóba mentem elsőkörben a data divet, az id alapján szelektorozva. Ezután pedig a backend szerverhez történő csatlakozáshoz szükséges url címet rögzítem változóba, amit később a Fecth API használatakor fogok alkalmazni.

function getDatasFromServer() {
let numberInputValue = document.querySelector("#numberInput").value
console.log(`SEND THIS NUMBER TO SERVER : ${numberInputValue}`)
let sendNumberToServer = new FormData()
sendNumberToServer.append("kapottadat", numberInputValue)

let FetchOptions = {
method: "POST", // *GET, POST, PUT, DELETE, etc.
mode: "cors", // no-cors, *cors, same-origin
body: sendNumberToServer,
cache: "no-cache"
};

fetch(backendUrl, FetchOptions)
.then((response) => response.json())
.then(function (data) {
console.log(data)
if(data.Error !== true){
dataDiv.innerHTML = ""
dataDiv.innerHTML += "Duplázás : " + data.Dupla + "</br>"
dataDiv.innerHTML += "Felezés : " + data.Felez + "</br>"
dataDiv.innerHTML += "Hozzáadás : " + data.Hozzaad + "</br>"
dataDiv.innerHTML += "Levonás : " + data.Levon + "</br>"
dataDiv.innerHTML += "Üdvözlés : " + data.Hello + "</br>"
dataDiv.innerHTML += "A küldött érték visszakapása a szervetől : " + data.Visszakap + "</br>"
} else {
dataDiv.innerHTML = ""
dataDiv.innerHTML += "Hiba a bevitt adatokban. Számot kell megadni"
}
})
.catch(function(error) {
console.error(error);
dataDiv.innerHTML = ""
dataDiv.innerHTML += "Hiba a szerverrel történő kommunikáció során"

});
}

getDatasFromServer() funkció. Ez az a funkció, amit submit gombra történő kattintáskor szeretnék lefuttatni. Ehhez fel kell venni az EventListener-re. Magyarul talán esemény hallgatónak lehetne nevezni. Ehhez a következő kódot kell betennünk a kódunkba.

submitButton.addEventListener('click', getDatasFromServer)

Mit mond ez a kód? A submitButtont, felvettem egy változóba, ezáltal meghatásoztam azt. Ezt szeretném hozzáadni az esemény hallgatóhoz amikor 'click'-elek. Melyik függvényt szeretném futtatni? A getDatasFromServer függvényt. Ezzel azt érem el, hogy a program végig megy a function getDatasFromServer() { .... } kapcsos zárójelei közé rakott kódon, ha lenyomom a submit gombot. Menjünk végig mi is ezen, sorról sorra.
Mi található a függvény kapcsos zárójelei között? Elsőként az, hogy az input mezőben megadott számot beteszem egy változóba. (let numberInputValue). Ezután az értéket ki is íratom a konzol logon.
Ezután nyitok egy új FormData interfészt. Amit egy változóban rögzítek. Bővebben a linkre kattintás után olvashatsz a FormData interfészről.
sendNumberToServer.append("kapottadat", numberInputValue) Ezzel a sorral, hozzáadom kulcs-érték párként az adatokat a FormData interfészhez. "kapottadat" a kulcs, aminek az értéke az input mezőbe beírt érték, ami majd a fent említett backend $_POST['kapottadat'] változójába fog kerülni. A Fetch API küldi el neki egy POST metódusban.

let FetchOptions = {
method: "POST", // *GET, POST, PUT, DELETE, etc.
mode: "cors", // no-cors, *cors, same-origin
body: sendNumberToServer,
cache: "no-cache"
};

A Fetch API használatához szükségünk van opció beállításra a szerver url megadása mellett. Ezt az opció rész egy objektumot vár, amiben megadhatjuk az egyes opciókat. Mi most négy opciót használunk csak. (Van több is)
method: "POST" ezzel mondjuk meg a Fetch API-nak, hogy POST metódust akarunk használni. Van még pár metódus (GET, PUT, DELETE), de ezt most nem részletezem. Nem tárgya a leírásnak.
mode: "cors" Ezt nagyon fontos megadnunk, ha a frontendünk más domainen van, mint ahová a backendet raktuk. Ez teszi lehetővé a cross-domain kommunikációt és a backendnél említett header("Access-Control-Allow-Origin: *");
body: sendNumberToServer Ez a kód, mondja meg, hogy mit is szeretnénk elküldeni a POST-ban. Látható, hogy a sendNumberToServer változót raktam ide, aminek a tartalma a FormData interfészben tárolt objektum a 'kapottadat' : 'InputMező.értéke' kulcs értékpárral.
Ha beállítottuk az opciokat, akkor indíthatjuk is a Fetch API-t

....
fetch(backendUrl, FetchOptions)
.then((response) => response.json())
....

A Fetch API indításához szükség van a szerver url címére és az opció objektumra. A szerver url címét már a JavaScript program elején rögzítettem egy változóban, a FetchOPtions változót, a benne lévő objektummal közvetlen a FetchAPI indítása előtt készítettem el. Ennek a kódsornak a hatására a FetchAPI elküldte a 'kapottadat' : 'InputMező.aktuálisértéke' kulcsértékpárt a szervernek, azaz a backendnek. Az a fent leírt kódsor alapján megcsinálja a számításokat, majd JSON választ fog adni, amit a következő .then-ben fel tudunk dolgozni.

...
.then(function (data) {
console.log(data)
if(data.Error !== true){
dataDiv.innerHTML = ""
dataDiv.innerHTML += "Duplázás : " + data.Dupla + "</br>"
dataDiv.innerHTML += "Felezés : " + data.Felez + "</br>"
dataDiv.innerHTML += "Hozzáadás : " + data.Hozzaad + "</br>"
dataDiv.innerHTML += "Levonás : " + data.Levon + "</br>"
dataDiv.innerHTML += "Üdvözlés : " + data.Hello + "</br>"
dataDiv.innerHTML += "A küldött érték visszakapása a szervetől : " + data.Visszakap + "</br>"
} else {
dataDiv.innerHTML = ""
dataDiv.innerHTML += "Hiba a bevitt adatokban. Számot kell megadni"
}
})
...

Ha megjött a JSON válasz, azt egy függvénynek adjuk át data nevű változóként. Emlékezzünk, hogy a PHP-nál is ez volt a változó, de itt nem azért használóm, mert itt is azt kéne, csak azért használom, hogy könnyebben érthető legyen.
Mit tesz ez a függvény. Ha a data.Error nem true (Emlékezzünk hogy mikor fut a backendünk az error true ágra. Igen, ha nem szám értéket kap vagy nem megy el a POST ezáltal az $_POST['kapottadat'] változó nem létezik a PHP backenden).
Viszont ha nem true, akkor jól dolgoztunk ezért a dataDiv.innerHTML részebe, azaz magába a data id-jű divjébe beírhatja a data.Dupla data.Felez ... stb értékeket, így a backend által kiszámított adatok megjelennek a frontendünkön.

...
.catch(function(error) {
console.error(error);
dataDiv.innerHTML = ""
dataDiv.innerHTML += "Hiba a szerverrel történő kommunikáció során"

});
...

Szerverekkel történő kommunikáció esetén gyakran előfordul, hogy valami nem sikerül. Nem megy a szerver, nincs meg a kellő fájl, vagy túlterhelt és nem ad választ. Ezeket az eseteket is szükséges lekezelni a frontenden. Ezeknek a hibáknak az elkapására szolgál a Catch. Ennek egy függvényt adhatunk meg. Ez a függvény fog lefutni hiba esetén. Így elkerülhetjük, hogy széttessen az oldalunk, esetlegesen.
Látható, hogy hiba esetén, kiíratom konzol logba a hibát, illetve dataDiv.innerHTML részébe a szerver kommunikációval kapcsolatos hiba tényét.

Ennyi az egész. :)

Nézzük meg ezt a gyakorlatban. Beírok egy számot az input mezőbe. Legyen mondjuk ez ötezer.
Lenyomtam a küldés gombot, máris indult a POST a szerver felé, benne az input mezőben lévő értékkel, ami ebben az esetben 5000. Ezután kiíródtak az adatok a szerver válasza függvényében.

Mi történt a backenden eközben?

Számolt, majd tömbből kiírta a JSON választ.

Köszönöm, hogy elolvastad. Ha kérdésed vagy észrevételed van az írással kapcsolatban, nyugodtan írj kommentet, illetve ha érdekel a Webfejlesztés világa, akkor gyere Facebook csoportunkba a Webfejlesztés Tanulószoba csoportba

A bejegyzéshez tartozó forráskódok itt érhetők el:
BACKEND
FRONTEND

Update:
Közben figyelmeztettek, hogy kicsivel kevesebb InnerHTML-el is meg lehet oldani. És tégyleg. Kicsit elvadultam vele :D

Kipróbálni pedig ITT tudod

Copyright © 2000-2021 PROHARDVER Informatikai Kft.