Backend elméleti alapok · 2. tananyag
Amikor egy mobilalkalmazás betölti a termékeket, amikor egy weboldal elküld egy űrlapot, amikor egy időjárás-widget lekéri a hőmérsékletet — szinte mindig ugyanaz történik: egy program HTTP-kérést küld egy másik program API-jának, és JSON-választ kap. Ez a világ legelterjedtebb backend-felülete, és ezt hívjuk REST API-nak.
GET, POST,
PUT, PATCH, DELETE) és a
státuszkódok;curl-lel és VS Code-ból.A HTTP (HyperText Transfer Protocol) az a „nyelv”, amelyen a kliens és a szerver beszél. Két alapszabálya van:
A https:// ugyanaz a HTTP, csak TLS-sel (Transport Layer
Security) titkosítva. Az adat így útközben nem olvasható és nem módosítható. Élesben ma már mindig
HTTPS-t használunk; fejlesztés közben a localhost HTTP-je is elfogadható.
A HTTP verziói: HTTP/1.1 (a legelterjedtebb, szöveges), HTTP/2 (bináris, párhuzamos), HTTP/3 (QUIC protokollon). A mi szempontunkból mindegyik ugyanúgy néz ki: kérés, válasz, metódus, státuszkód, fejlécek, törzs.
| Rész | Szerep | Megjegyzés |
|---|---|---|
| Séma | http vagy https | A protokoll |
| Host | Melyik gépet keressük | A DNS oldja fel IP-címre |
| Port | Melyik programot a gépen | Elhagyható, ha alapértelmezett (80 / 443) |
| Path | Melyik erőforrást kérjük | Ez a REST szíve |
| Query | Szűrés, rendezés, lapozás | ?kulcs=érték&kulcs2=érték2 |
| Fragment | Az oldalon belüli hely | A szerverhez el sem jut! |
A query stringben lévő adat megjelenik a böngésző előzményeiben, a szerver naplóiban és a hivatkozó fejlécekben. Jelszót, tokent, személyes adatot soha ne tegyél az URL-be — annak a kérés törzsében vagy fejlécében a helye.
Mindkettő négy részből áll: kezdősor · fejlécek · üres sor · törzs.
GET-nek például nincs).| Fejléc | Mire való | Példa |
|---|---|---|
Content-Type | Milyen formátumú a küldött törzs | application/json |
Accept | Milyen formátumú választ várunk | application/json |
Authorization | Hitelesítő adat | Bearer <token> |
User-Agent | Milyen program küldi | Mozilla/5.0 … |
Cookie | A böngésző sütijei | session=abc123 |
A Content-Type arról szól, amit küldesz; az
Accept arról, amit kapni szeretnél. Ezt kezdők gyakran összekeverik.
A metódus azt mondja meg, mit akarunk tenni az erőforrással. Ugyanaz az URL egészen mást jelent attól függően, melyik metódussal hívjuk meg — nézzük végig őket egyesével.
GET — kérd le!A leggyakoribb metódus: adatot kérünk, de nem változtatunk semmit. Ez az egyetlen, amit a böngésző címsorába beírva is ki tudsz próbálni, és ezt használja a böngésző minden képhez, CSS-fájlhoz, oldalhoz. Nincs törzse: amit közölni akarsz vele (szűrés, lapozás), az az URL query részébe kerül. Mivel nem változtat, a válasza nyugodtan gyorsítótárazható.
POST — hozz létre újat!Új erőforrás létrehozására való: új termék, új rendelés, új felhasználó. Az adatot a kérés törzsében küldjük, JSON-ban. A szerver dönti el, milyen azonosítót kap az új elem — ezért a válaszban kapjuk vissza. Ha kétszer küldöd el, két dolog jön létre: ez a metódus nem ismételhető büntetlenül. (Ezen kívül a POST a „gyűjtőhely” minden olyan műveletnek, ami nem fér bele a CRUD-ba — például a bejelentkezés.)
PUT — cseréld le az egészet!Egy létező erőforrás teljes felülírása. Fontos: a PUT-nál az erőforrás minden mezőjét el kell küldeni, mert amit kihagysz, az elveszik — a szerver a beküldött állapotra cseréli a régit. Ha ötször küldöd el ugyanazt, ötször ugyanaz lesz az eredmény, ezért idempotens.
PATCH — módosíts egy részletet!Akkor használjuk, ha csak néhány mezőt akarunk megváltoztatni. Ha egy termék árát kell
átírni, PATCH-csel elég ennyit küldeni: { "price": 29990 } — a név, a leírás és a
kategória érintetlen marad. PUT-tal ugyanezért az egész terméket újra be kellene küldeni.
A tanuló a webshop admin felületén átírja egy termék árát:
PUT /products/42 →
{ "name": "Billentyűzet", "price": 29990, "categoryId": 3, "description": "…" }
Minden mezőt küldeni kell. Ha a description
lemarad, a szerver törli.
PATCH /products/42 →
{ "price": 29990 }
Csak a változó mező megy át. A többi marad, ahogy volt.
DELETE — töröld!Az erőforrás törlése. Általában nincs törzse (minden információ benne van az URL-ben), és sikeres törlés után jellemzően nincs mit visszaadni. Idempotens: ha másodszor is elküldöd, a termék ugyanúgy nem lesz meg — az állapot tehát ugyanaz marad, még ha a második kérés 404-et is kap.
HEAD — csak a fejléceket kérem!Pontosan ugyanaz, mint a GET, de a szerver csak a fejléceket küldi
vissza, a törzset nem. Arra jó, hogy valamit megtudj az erőforrásról anélkül, hogy letöltenéd:
létezik-e egyáltalán, mekkora (Content-Length), mikor változott utoljára.
Például egy letöltőprogram ezzel nézi meg egy 2 GB-os fájl méretét, mielőtt nekikezdene.
OPTIONS — mit tudsz, végpont?Azt kérdezi meg, milyen metódusokat fogad el az adott útvonal; a válasz egy
Allow fejlécben sorolja fel őket. A gyakorlatban ritkán írod le kézzel — viszont
a böngésző magától küldi az ún. előkérésekben (preflight), amikor egy oldal más eredetű
API-t hív. Ha a hálózati fülön furcsa OPTIONS-kéréseket látsz a saját kérésed előtt, az a
CORS működése.
| Metódus | Jelentés | CRUD | Van törzse? | Biztonságos? | Idempotens? |
|---|---|---|---|---|---|
| GET | Lekérés | Read | Nincs | ✅ | ✅ |
| POST | Új létrehozása | Create | Van | ❌ | ❌ |
| PUT | Teljes lecserélés | Update | Van | ❌ | ✅ |
| PATCH | Részleges módosítás | Update | Van | ❌ | ❌* |
| DELETE | Törlés | Delete | Általában nincs | ❌ | ✅ |
| HEAD | Mint a GET, de csak fejlécek | — | Nincs | ✅ | ✅ |
| OPTIONS | Mit tud ez a végpont? | — | Nincs | ✅ | ✅ |
* A PATCH lehet
idempotens, ha jól tervezzük, de a szabvány nem garantálja.
Biztonságos (safe): a kérés nem változtat a szerver állapotán.
A GET csak olvas.
Klasszikus kezdő hiba: GET /products/42/delete. A böngésző, a keresőrobot
vagy egy gyorsítótár bármikor „csak úgy” meglátogathat egy GET-címet — és ezzel véletlenül törölhet.
Törlésre mindig DELETE metódus való.
Idempotens: ha ugyanazt a kérést többször elküldöd, az eredmény ugyanaz, mintha egyszer küldted volna.
| Kérés | Egyszer | Ötször | Idempotens? |
|---|---|---|---|
GET /products/42 | Visszaadja a terméket | Visszaadja a terméket | ✅ |
PUT /products/42 {ar: 1000} | Az ár 1000 lesz | Az ár 1000 marad | ✅ |
DELETE /products/42 | Törli | Már nincs mit törölni — az állapot ugyanaz | ✅ |
POST /orders | 1 rendelés jön létre | 5 rendelés jön létre | ❌ |
Amikor újratöltéskor felugrik, hogy „biztosan újraküldi az űrlapot?”, az pontosan azért van, mert a
POST nem idempotens, és kétszer is végrehajtódhat. Ez a valóságban is probléma
(dupla rendelés), ezért a fizetéseknél idempotencia-kulcsot szoktak használni.
A státuszkód három számjegy, és az első számjegy adja a kategóriát.
| Kód | Név | Mikor használjuk? |
|---|---|---|
| 200 | OK | Sikeres GET, PUT, PATCH — van válasz-törzs |
| 201 | Created | Sikeres POST: új erőforrás jött létre. Adjunk Location fejlécet is! |
| 204 | No Content | Sikeres művelet, de nincs mit visszaadni (tipikusan DELETE) |
| 304 | Not Modified | A gyorsítótárban lévő változat még jó |
| 400 | Bad Request | Hibás, értelmezhetetlen kérés (pl. rossz JSON) |
| 401 | Unauthorized | Nem vagy bejelentkezve (hiányzik vagy lejárt a token) |
| 403 | Forbidden | Be vagy jelentkezve, de nincs jogosultságod |
| 404 | Not Found | Nincs ilyen erőforrás |
| 405 | Method Not Allowed | Létező útvonal, de ezzel a metódussal nem használható |
| 409 | Conflict | Ütközés (pl. már létezik ilyen e-mail cím) |
| 415 | Unsupported Media Type | Nem támogatott Content-Type |
| 422 | Unprocessable Content | A kérés formailag jó, de tartalmilag hibás (validációs hiba) |
| 429 | Too Many Requests | Túl sok kérés rövid idő alatt (rate limiting) |
| 500 | Internal Server Error | Kezeletlen hiba a szerveren |
| 502 503 | Bad Gateway / Service Unavailable | Nem érhető el vagy nem válaszol a mögöttes szolgáltatás |
401 Unauthorized: „Nem tudom, ki vagy.” → jelentkezz be.
403 Forbidden: „Tudom, ki vagy, de ezt nem teheted.” → nincs jogod hozzá.
A név megtévesztő: a 401 valójában hitelesítési, nem jogosultsági hiba.
Bevett gyakorlat: a kérés formája hibás (érvénytelen JSON) → 400;
a kérés jó formájú, de az adat nem érvényes (negatív ár, hiányzó kötelező mező) →
422. Sok API mindkét esetben 400-at ad — a lényeg, hogy
következetes légy.
Ez a fejezet legfontosabb gyakorlati készsége. Nyolc helyzet — válaszd ki a helyes kódot!
A JSON (JavaScript Object Notation) egy szöveges adatformátum. A JavaScript objektum-szintaxisából származik, de ma már minden programozási nyelv kezeli.
{
"id": 42,
"name": "Mechanikus billentyűzet",
"price": 34990,
"inStock": true,
"discount": null,
"tags": ["billentyűzet", "gaming"],
"category": {
"id": 3,
"name": "Perifériák"
}
}
| Típus | Példa |
|---|---|
| szöveg (string) | "Anna" — csak kettős idézőjel! |
| szám (number) | 42, 3.14, -7 (nincs külön egész és tört) |
| logikai (boolean) | true, false |
| null | null |
| tömb (array) | [1, 2, 3], ["a", "b"] |
| objektum (object) | { "kulcs": "érték" } |
| Hiba | ❌ Rossz | ✅ Jó |
|---|---|---|
| Aposztróf | { 'nev': 'Anna' } | { "nev": "Anna" } |
| Idézőjel nélküli kulcs | { nev: "Anna" } | { "nev": "Anna" } |
| Záró vessző | { "a": 1, } | { "a": 1 } |
| Komment | // megjegyzés | (nincs JSON-ban komment) |
| Dátum típus | 2026-03-15 | "2026-03-15T10:30:00Z" |
Függvény, undefined | { "f": () => 1 } | (nem létezik JSON-ban) |
Mindig ISO 8601 formátumban, UTC-ben küldjük: "2026-03-15T10:30:00.000Z".
Így nincs félreértés a 03/15 és a 15/03 között.
// Objektum → JSON-szöveg const szoveg = JSON.stringify({ nev: "Anna", kor: 17 }); // '{"nev":"Anna","kor":17}' // JSON-szöveg → objektum const objektum = JSON.parse('{"nev":"Anna","kor":17}'); // { nev: 'Anna', kor: 17 }
Fontos: a hálózaton szöveg utazik. A JSON.
és a JSON. a fordítók a szöveg és az objektum között. (Express-szel ezt
később nagyrészt automatikusan megkapjuk.)
Írd át a szöveget, és nézd meg, mit mond rá a JSON. —
ugyanaz az elemző fut, mint a szerveren.
A JSON előtt az XML (eXtensible Markup Language) volt az adatcsere szabványa — a 2000-es évek web-szolgáltatásai szinte kivétel nélkül ezt használták, és sok vállalati rendszer ma is így beszél. Az XML felépítése ismerős lesz: ugyanolyan elemekből áll, mint a HTML — nyitó és záró tagekből —, csak a tagek nevét te találod ki.
Nézzük meg ugyanazt a terméket mindkét formátumban:
{
"id": 42,
"name": "Mechanikus billentyűzet",
"price": 34990,
"inStock": true,
"tags": ["billentyűzet", "gaming"],
"category": { "id": 3, "name": "Perifériák" }
}
<?xml version="1.0" encoding="UTF-8"?> <product> <id>42</id> <name>Mechanikus billentyűzet</name> <price>34990</price> <inStock>true</inStock> <tags> <tag>billentyűzet</tag> <tag>gaming</tag> </tags> <category> <id>3</id> <name>Perifériák</name> </category> </product>
A tartalom pontosan ugyanannyi, a JSON mégis nagyjából feleakkora. Az XML minden adatdarabot kétszer nevez meg (nyitó és záró tag), és a legtöbb API-nál ez a többlet semmit nem ad hozzá.
<price>34990</price>
és a <inStock>true</inStock> egyaránt karakterlánc — a fogadó
programnak külön kell tudnia, hogy az egyiket számmá, a másikat logikai értékké alakítsa.
A JSON-ban a 34990 szám, a true logikai érték:
a típus benne van a formátumban.[…]). Az XML-ben ehhez ki kell találni egy burkoló elemet
(<tags>), és megegyezni, hogy az ismétlődő gyerekelemek alkotják a
listát. Egyetlen elemnél ráadásul nem is egyértelmű, hogy az lista-e vagy sem.<product id="42">). Ezért ugyanazt az adatot többféleképpen lehet
leírni, és a két oldalnak meg kell egyeznie, melyiket használják. A JSON-ban erre nincs választás.JSON.parse
egy sor, és kész JavaScript-objektumot ad. XML-hez elemző kell, az eredmény pedig egy DOM-fa, amit
csomópontonként kell bejárni — jóval több kód ugyanazért az adatért.| Szempont | JSON | XML |
|---|---|---|
| Méret | Kisebb | Nagyobb (nyitó + záró tagek) |
| Adattípusok | Beépített (szám, logikai, null, tömb) | Nincs — minden szöveg |
| Lista | Természetes ([…]) | Megegyezés kérdése |
| Feldolgozás JavaScriptben | JSON. — beépített | Külön elemző, DOM-bejárás |
| Séma, érvényesítés | Külön eszközzel (JSON Schema, Zod) | Beépített, erős (XSD) |
| Megjegyzés a fájlban | Nem lehet | Lehet |
| Elterjedtség web-API-kban | Uralkodó | Régebbi, vállalati rendszerek (SOAP) |
Nem — csak másra jó. Ahol a dokumentum szerkezete a lényeg (szövegek jelölése, kiadványok, konfigurációs szabványok), ott az XML erősebb: van hozzá szigorú séma (XSD), névtér-kezelés és lekérdezőnyelv (XPath). Programok közti adatcserére viszont a JSON kisebb, egyszerűbb és típusosabb — ezért lett ez a web-API-k formátuma.
Az API (Application Programming Interface) két program közötti „szerződés”: leírja, hogyan lehet egy szolgáltatás funkcióit használni.
Az étterem étlapja. Nem kell tudnod, hogyan működik a konyha; elég, hogy van egy lista arról, mit rendelhetsz és mit kapsz érte. Az étlap az API, a konyha az implementáció.
A web-API olyan API, amelyet HTTP-n keresztül lehet elérni. Ilyen a REST is.
A REST (REpresentational State Transfer) egy architekturális stílus, amelyet Roy Fielding írt le 2000-ben, a doktori disszertációjában. Fielding egyike volt a HTTP/1.1 szabvány szerzőinek — a REST tulajdonképpen annak összefoglalása, hogyan van kitalálva a web, és hogyan érdemes ezt az API-knál is követni.
A REST nem szabvány, nem protokoll és nem könyvtár. Nem lehet „telepíteni”. Ez egy elvrendszer, ajánlások összessége. Ezért van, hogy két REST API sem néz ki teljesen egyformán — és ezért vitatkoznak a fejlesztők azon, „mennyire RESTes” egy API.
A központi gondolat: minden dolog erőforrás (resource), amelynek van egy címe (URI), és amelyet egységes műveletekkel (HTTP-metódusokkal) kezelünk.
NEM így gondolkodunk: Hanem így: "hívjuk meg a termékTörlés()-t" → "töröljük a /products/42 erőforrást" (műveletközpontú) (erőforrás-központú)
Fielding hat megszorítást (constraint) fogalmazott meg. Ezek együtt adják a REST-et.
A felhasználói felület és az adattárolás külön fejlődik. Ugyanazt az API-t használhatja weboldal, mobilapp és külső partner is.
A szerver nem tárol munkamenet-állapotot a kérések között. Minden kérésnek magában kell hordoznia mindent, ami a feldolgozásához kell — így a hitelesítő adatot is.
Állapotmentes ≠ adatmentes! Az adatok természetesen az adatbázisban maradnak. Csak a munkamenet nem él a szerver memóriájában.
A válaszok megjelölhetők, hogy eltárolhatók-e és meddig (Cache-Control,
ETag). Így a kliens vagy egy köztes réteg (CDN — Content Delivery Network) újra
felhasználhatja őket: kevesebb hálózat, gyorsabb alkalmazás.
Ez a REST védjegye. Négy összetevője:
/products/42);Content-Type megmondja, mit küldtünk;
a státuszkód, mi lett az eredmény;A kliens nem tudja (és nem is kell tudnia), hogy közvetlenül a szerverrel beszél-e, vagy egy köztes réteggel (proxy, terheléselosztó, gyorsítótár). Bármikor beszúrható közéjük réteg.
A szerver futtatható kódot is küldhet a kliensnek (például JavaScriptet). Ez az egyetlen nem kötelező alapelv, és a gyakorlatban ritkán számít az API-knál.
Hypermedia As The Engine Of Application State. Azt jelenti, hogy a válasz tartalmazza, „innen hova mehetsz tovább”:
{ "id": 42, "name": "Billentyűzet",
"_links": { "self": "/api/products/42", "category": "/api/categories/3" } }
Elméletileg ez a „teljes” REST része, a gyakorlatban a legtöbb API kihagyja, mert bonyolítja a fejlesztést. Mi sem fogjuk használni, de tudnod kell, hogy létezik.
Hasznos skála arra, „mennyire RESTes” egy API:
Ez a rész a fejezet legfontosabb gyakorlati tudása.
| Szabály | ❌ Rossz | ✅ Jó |
|---|---|---|
| Főnév, ne ige — az igét a metódus adja | /getProducts, /createProduct | GET /products, POST /products |
| Többes szám a gyűjteményeknek | /product/42 | /products/42 |
| Kisbetű, kötőjel | /OrderItems, /order_items | /order-items |
| Hierarchia a kapcsolatokhoz | /getOrdersOfUser?id=5 | /users/5/orders |
| Ne legyen kiterjesztés | /products. | /products (+ Accept fejléc) |
| Szűrés query stringben | /products/cheap | /products?maxPrice=5000 |
| Ne legyen záró perjel | /products/ | /products |
| Cél | Metódus + útvonal | Siker |
|---|---|---|
| Összes termék listája | GET /api/products | 200 |
| Egy termék lekérése | GET /api/products/42 | 200 |
| Új termék létrehozása | POST /api/products | 201 + Location |
| Termék teljes felülírása | PUT /api/products/42 | 200 |
| Termék részleges módosítása | PATCH /api/products/42 | 200 |
| Termék törlése | DELETE /api/products/42 | 204 |
| Egy termék értékelései | GET /api/products/42/reviews | 200 |
| Új értékelés a termékhez | POST /api/products/42/reviews | 201 |
Ezek nem külön végpontok, hanem query paraméterek ugyanazon a gyűjteményen:
GET /api/products?categoryId=3 // szűrés GET /api/products?minPrice=1000&maxPrice=5000 GET /api/products?sort=price&order=asc // rendezés GET /api/products?page=2&limit=20 // lapozás GET /api/products?q=billentyuzet // keresés GET /api/products?fields=id,name,price // mezőválasztás
Lapozásnál a válasz általában metaadatot is tartalmaz:
{
"data": [ { "id": 21, "name": "…" }, { "id": 22, "name": "…" } ],
"meta": { "page": 2, "limit": 20, "total": 137, "totalPages": 7 }
}
Válaszd ki a metódust, az útvonalat és a paramétereket a feladathoz — aztán nézd meg, mit szólna hozzá a szerver.
Nem minden művelet „létrehozás/olvasás/módosítás/törlés”. Mit kezdjünk a bejelentkezéssel vagy egy rendelés lemondásával? Két bevett megoldás:
POST /orders/42/cancellation —
létrehozunk egy „lemondást”.POST /auth/login,
POST /orders/42/cancel.A második megoldás nem „tiszta” REST, de elterjedt és elfogadott. A jó API a kiszámíthatóságot szolgálja, nem a szabálykövetés kedvéért létezik.
Ha az API úgy változik, hogy a régi kliensek eltörnek, verziózni kell:
| Mód | Példa | Megjegyzés |
|---|---|---|
| URL-ben | /api/v1/products | A legelterjedtebb, jól látható — mi ezt használjuk |
| Fejlécben | Accept: application/vnd. | „Tisztább”, de nehezebben tesztelhető |
| Query-ben | /api/products?version=1 | Ritkább |
GET /api/v1/products?categoryId=3&limit=2 HTTP/1.1 Host: api.webshop.hu Accept: application/json
HTTP/1.1 200 OK Content-Type: application/json { "data": [ { "id": 42, "name": "Mechanikus billentyűzet", "price": 34990, "inStock": true }, { "id": 43, "name": "Vezeték nélküli egér", "price": 12990, "inStock": false } ], "meta": { "page": 1, "limit": 2, "total": 17 } }
POST /api/v1/products HTTP/1.1 Content-Type: application/json Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... { "name": "Gamer fejhallgató", "price": 24990, "categoryId": 3 }
HTTP/1.1 201 Created Location: /api/v1/products/58 Content-Type: application/json { "id": 58, "name": "Gamer fejhallgató", "price": 24990, "categoryId": 3, "createdAt": "2026-03-15T10:30:00.000Z" }
POST /api/v1/products HTTP/1.1 Content-Type: application/json { "name": "", "price": -500 }
HTTP/1.1 422 Unprocessable Content Content-Type: application/json { "error": { "code": "VALIDATION_ERROR", "message": "A megadott adatok érvénytelenek.", "details": [ { "field": "name", "message": "A név megadása kötelező." }, { "field": "price", "message": "Az ár nem lehet negatív." } ] } }
DELETE /api/v1/products/42 HTTP/1.1 Authorization: Bearer <egy sima felhasználó tokenje>
HTTP/1.1 403 Forbidden Content-Type: application/json { "error": { "code": "FORBIDDEN", "message": "Ehhez a művelethez adminisztrátori jog szükséges." } }
Válassz egy hibaszerkezetet, és az egész API-ban ugyanazt használd. A kliensfejlesztő így egyszer írja meg a hibakezelést, és minden végpontnál működni fog.
Ha nem akarsz saját hibaszerkezetet kitalálni, használhatod az RFC 9457 szabványt
(„Problem Details for HTTP APIs”). Ennél a válasz Content-Type fejléce nem
application/json, hanem application/problem+json,
a törzs pedig előre megbeszélt mezőneveket használ:
HTTP/1.1 422 Unprocessable Content Content-Type: application/problem+json { "type": "https://api.webshop.hu/hibak/ervenytelen-adat", "title": "A megadott adatok érvénytelenek.", "status": 422, "detail": "Az ár nem lehet negatív, a név pedig kötelező.", "instance": "/api/v1/products", // a szabvány engedi, hogy saját mezőkkel bővítsd: "errors": [ { "field": "name", "message": "A név megadása kötelező." }, { "field": "price", "message": "Az ár nem lehet negatív." } ] }
| Mező | Mit tartalmaz? |
|---|---|
type | A hibatípus azonosítója — jellemzően egy URL, ahol el is olvasható a magyarázata |
title | Rövid, ember által olvasható cím. Ugyanahhoz a type-hoz mindig ugyanaz |
status | A HTTP-státuszkód megismételve a törzsben |
detail | Ehhez a konkrét esethez tartozó magyarázat |
instance | Melyik kérésnél történt (útvonal vagy hibaazonosító) |
Miért jó ez? Mert a mezőnevek nem a te fejedből származnak: egy külső fejlesztő, aki még
soha nem látta az API-dat, a Content-Type-ból azonnal tudja, mire számítson.
Számos keretrendszerhez létezik hozzá kész kliensoldali kezelő is.
A webshop-projektben a fentebb bemutatott, egyszerűbb saját { "error": { … } }
szerkezetet fogjuk használni — kevesebb ceremónia, és tanulni is könnyebb rajta. Azért ismerd az RFC 9457-et,
mert éles projektekben és publikus API-kban gyakran ezzel fogsz találkozni.
A hibaüzenet soha ne szivárogtasson belső információt: SQL-lekérdezést, fájlútvonalat, stack trace-t, könyvtárneveket. Ezek a támadónak adnak segítséget. A részletes hiba a naplóba való, a kliens csak általános üzenetet kapjon.
| Előny | Magyarázat |
|---|---|
| Egyszerű és ismerős | A HTTP-re épül, amit minden fejlesztő és minden eszköz ismer |
| Platformfüggetlen | A szerver Node.js, a kliens Android — nem számít |
| Jól skálázható | Az állapotmentesség miatt tetszőleges számú szerver mögé tehető |
| Gyorsítótárazható | A GET-válaszok cache-elhetők (böngésző, CDN, proxy) |
| Kliensfüggetlen | Ugyanazt az API-t használja a web, a mobil és a partnerrendszer |
| Könnyen tesztelhető | Böngészőből, curl-lel, REST Clienttel azonnal kipróbálható |
| Kiváló eszköztámogatás | OpenAPI-dokumentáció, generátorok, tesztelők |
| Fokozatosan fejleszthető | Új végpontok adhatók hozzá a régiek törése nélkül |
| Hátrány | Magyarázat | Enyhítés |
|---|---|---|
| Túl sok adat (over-fetching) | A /users/5 mindent visszaad, pedig csak a név kellett | ?fields= paraméter |
| Túl kevés adat (under-fetching, N+1 kérés) | A lista után minden elemhez külön kérés kell | Beágyazás (?include=category) vagy GraphQL |
| Nincs szigorú szerződés | A REST nem írja elő a válasz szerkezetét | OpenAPI-leírás, TypeScript-típusok |
| Merev erőforrás-modell | Bonyolult műveletek nehezen erőltethetők CRUD-ba | Művelet-alerőforrások |
| Verziózási teher | A változás könnyen töri a régi klienseket | Verziózás, visszafelé kompatibilitás |
| Szöveges és terjengős | A JSON nagyobb, mint egy bináris formátum | Tömörítés (gzip, brotli), gRPC belső hívásokra |
| Nincs valós idejű támogatás | A szerver nem tud magától szólni | WebSocket vagy SSE külön |
Lekéred a 20 terméket (1 kérés), majd mindegyikhez külön lekéred a kategóriáját (20 kérés) — összesen 21 hálózati kör. Ugyanez a probléma az adatbázisban is felbukkan majd a Prismánál; ott is ugyanígy hívjuk.
A REST megmondja, hogyan címezd az erőforrásokat, de arról egy szót sem szól, milyen
mezők vannak a válaszban. Semmi nem akadályozza meg a backend-fejlesztőt abban, hogy holnap
átnevezze a price mezőt amount-ra — a kérés
ugyanúgy 200-at fog adni, csak a mobilalkalmazásban mostantól
„undefined Ft” jelenik meg.
A gRPC-nél vagy a GraphQL-nél ez nem történhet meg: ott a mezőlista géppel olvasható szerződésben van rögzítve, és a fordító azonnal szól, ha valaki elrontja. REST-nél ezt a szerződést nekünk kell pótolnunk:
A tanulság: a REST szabadsága kényelmes fejlesztés közben, de a fegyelmet nekünk kell hozzátennünk — különben az API némán romlik el a kliensek alatt.
A REST abból indul ki, hogy minden művelet besorolható a négy CRUD-művelet valamelyikébe: létrehozás, olvasás, módosítás, törlés. Csakhogy a valóságban rengeteg olyan művelet van, amelyik egyik dobozba sem fér bele:
| A művelet, amit szeretnénk | Melyik CRUD ez? |
|---|---|
| Bejelentkezés jelszóval | Nem hoz létre semmit… vagy egy „munkamenetet” igen? |
| Egy rendelés lemondása | Módosítás? Törlés? A rendelés megmarad, csak az állapota változik. |
| Elfelejtett jelszó — e-mail küldése | Semmit nem hoz létre a felhasználó szemszögéből. |
| Két felhasználói fiók összevonása | Egyszerre módosítás és törlés, két erőforráson. |
| Egy termék készletének növelése eggyel | Módosítás — de az új érték a régitől függ. |
Ilyenkor két úton indulhatunk el. Vagy találunk egy főnevet a művelet mögé, és
létrehozzuk azt (POST /orders/42/cancellation — létrejön egy „lemondás”),
vagy elfogadjuk, hogy itt kivételt teszünk, és igét használunk
(POST /auth/login).
Fontos, hogy ez nem hiba, hanem kompromisszum. Aki mindenáron erőforrásokba akar gyömöszölni minden műveletet, olyan URL-eket gyárt, amit senki nem ért. A jó API elsősorban kiszámítható, és csak másodsorban elvhű.
| Szempont | REST | GraphQL | gRPC | SOAP |
|---|---|---|---|---|
| Formátum | JSON (általában) | JSON | Bináris (Protobuf) | XML |
| Végpontok | Sok (erőforrásonként) | Általában egy | Szolgáltatás-metódusok | Egy |
| Ki dönti el, mi jön vissza | A szerver | A kliens | A szerződés | A szerződés |
| Szerződés, típusok | Laza (OpenAPI ajánlott) | Erős (séma) | Erős (.) | Erős (WSDL) |
| Böngészőből hívható | ✅ | ✅ | ⚠️ csak proxyval | ✅ |
| HTTP-gyorsítótár | ✅ | ⚠️ nehézkes | ⚠️ | ⚠️ |
| Tanulási görbe | Alacsony | Közepes | Közepes-magas | Magas |
| Tipikus felhasználás | Publikus és belső web-API | Sokféle kliens, összetett adat | Szolgáltatások közti belső hívás | Régi vállalati rendszerek |
Mert ez a legelterjedtebb, a legegyszerűbben megérthető, és mert a mögötte lévő tudás — HTTP, státuszkódok, JSON — minden másik megoldásnál is kell.
Ezeket most csak megismerjük — a webshop-projektben mindegyikkel dolgozni fogunk.
A böngésző alapból megtiltja, hogy egy oldal (http://localhost:5173)
más eredetű (http://localhost:3000) API-t hívjon. A szervernek külön engedélyt kell
adnia erre (Access-Control-Allow-Origin fejléc).
Ez a kezdők egyik leggyakoribb „miért nem működik?” élménye — és csak a böngészőt érinti:
curl-lel vagy REST Clienttel ugyanaz a kérés simán működik. Ha tehát a
böngészőben CORS-hibát látsz, de a REST Clientben minden jó, akkor nem a szerver logikájával van baj.
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI1IiwiZXhwIjoxNzQyMH0.abc123def456ghi
└───── fejléc ─────┘ └──────────── adat ───────────┘ └── aláírás ──┘
melyik algoritmus ki vagy, meddig érvényes ezzel ellenőrzi
írta alá a szerver
A JWT (JSON Web Token) három, ponttal elválasztott részből áll. Nem titkosított, csak aláírt — bárki elolvashatja a tartalmát, de módosítani nem tudja észrevétlenül.
Mivel a token tartalma olvasható, jelszót vagy más érzékeny adatot soha ne tegyünk bele. Csak azonosítót, szerepkört és lejárati időt.
Korlátozzuk, hány kérést küldhet valaki adott idő alatt. Túllépés esetén
429 Too Many Requests. Véd a visszaélés és a
jelszó-próbálgatás ellen.
Éles rendszerben kötelező. Enélkül a tokened és a jelszavad olvasható a hálózaton.
Géppel olvasható leírás az API-ról, amelyből kipróbálható dokumentációs felület és kliens-kódok generálhatók.
| Eszköz | Mire jó | Megjegyzés |
|---|---|---|
| Böngésző címsora | Csak GET-re | A leggyorsabb ellenőrzés |
| DevTools → Network | Valós kérések megfigyelése | F12, majd frissítés |
curl | Bármilyen kérés parancssorból | Windows 10/11-en beépített |
| REST Client (VS Code) | . fájlba írt kérések | Ingyenes, verziókezelhető — ezt ajánljuk |
| Bruno | Önálló API-kliens | Ingyenes, nyílt forráskódú, fájlalapú |
| Postman / Insomnia | Önálló API-kliens | Ingyenes csomaggal is használható, de fiókot kér |
# GET-kérés curl https://jsonplaceholder.typicode.com/users/1 # GET a fejlécekkel együtt curl -i https://jsonplaceholder.typicode.com/users/1 # POST JSON-nal (cmd-ben a folytatójel ^, PowerShellben `, Linuxon \) curl -X POST https://jsonplaceholder.typicode.com/posts ^ -H "Content-Type: application/json" ^ -d "{\"title\":\"Teszt\",\"body\":\"Szöveg\",\"userId\":1}"
PowerShellben a curl alapból az Invoke-WebRequest
álneve lehet, és másképp viselkedik. Használd a curl. alakot, vagy dolgozz
a VS Code REST Clientjével.
keresek.http )### Felhasználó lekérése GET https://jsonplaceholder.typicode.com/users/1 Accept: application/json ### Új bejegyzés POST https://jsonplaceholder.typicode.com/posts Content-Type: application/json { "title": "Teszt", "body": "Szöveg", "userId": 1 }
Kattints egy kérésre, és nézd meg, mit válaszolna rá a webshop API-ja. Figyeld a státuszkódot és a válasz szerkezetét! (Ez itt beégetett adatokból dolgozik, valódi hálózat nélkül.)
| ❌ Rossz | ✅ Jó | Miért |
|---|---|---|
GET /getAllProducts | GET /products | Az igét a metódus adja |
POST /deleteProduct?id=42 | DELETE /products/42 | Megfelelő metódus |
GET /products/42/delete | DELETE /products/42 | A GET nem változtathat állapotot |
200 { "error": "nincs jog" } | 403 Forbidden | A státuszkód hordozza az eredményt |
POST /products → 200 | 201 + Location | Pontos jelzés a létrehozásról |
/products?deleteId=42 | DELETE /products/42 | Az azonosító az útvonalba való |
/product/42/reviews/list | /products/42/reviews | Következetes többes szám, felesleges tag nélkül |
GET /login?user=a&pass=b | POST /auth/login (törzsben) | Jelszó soha nem megy URL-ben |
| Minden hiba 500 | 400 / 401 / 403 / 404 / 409 / 422 | Segít a hibakeresésben |
| Válasz hol tömb, hol objektum | Egységes szerkezet | Kiszámíthatóság |
| Hiba | Miért baj | Helyesen |
|---|---|---|
| Ige az URL-ben | Nem erőforrás-orientált | POST /users |
| Állapotváltoztatás GET-tel | Cache vagy robot véletlenül végrehajtja | Megfelelő metódus |
| Mindig 200 | A kliens nem tudja, mi történt | Beszédes státuszkódok |
| Token az URL-ben | Naplókban, előzményekben megmarad | Authorization fejléc |
| Stack trace a hibaválaszban | Információszivárgás | Általános üzenet + naplózás |
| Nincs validáció a szerveren | A kliens megkerülhető | Minden bemenet ellenőrzése |
| Egyes és többes szám keverése | Kiszámíthatatlan API | Következetes többes szám |
| Nincs lapozás a listáknál | 100 000 rekord egy válaszban | page + limit |
| Jelszó-hash visszaküldése | Súlyos biztonsági hiba | Sosem küldünk vissza titkot |
Metódus és státuszkód. Add meg minden művelethez a helyes metódust, útvonalat és sikeres
státuszkódot egy blog API-ban (erőforrások: posts, comments):
Státuszkód-választás. Melyik státuszkódot adnád vissza?
Hibakeresés. Javítsd ki az alábbi API-tervet, és indokold soronként!
GET /api/getAllUsers POST /api/user/delete?id=5 GET /api/user/5/getOrders POST /api/login?email=a@b.hu&password=titok123 GET /api/products/cheap
Idempotencia. Döntsd el, idempotens-e, és indokolj!
GET /orders/3 b) POST /ordersPUT /users/5 { "name": "Anna" }DELETE /users/5PATCH /products/42 { "stock": { "increaseBy": 1 } }JSON-javítás. Keresd meg a hibákat! (Az ellenőrzéshez használd a 6. szakasz JSON-ellenőrzőjét.)
{
nev: 'Kovács Anna',
"kor": 17,
"aktiv": True,
"targyak": ["matek", "fizika",],
// megjegyzés
"szuletett": 2026-05-14
}
API-terv. Tervezd meg egy iskolai könyvtár API-jának végpontjait! Erőforrások: könyvek, szerzők, olvasók, kölcsönzések. Adj meg legalább 12 végpontot metódussal, útvonallal, rövid leírással és a sikeres státuszkóddal. Gondolj a szűrésre és a lapozásra is!
Előny-hátrány esszé. Egy cég azon gondolkodik, REST vagy GraphQL API-t készítsen a mobilalkalmazásához. Írj fél oldalt: milyen kérdéseket tennél fel nekik, és milyen esetben ajánlanád az egyiket vagy a másikat?
Böngészős felfedezés. Nyisd meg ezeket a címeket, és jegyezd le, mit adnak vissza:
https://jsonplaceholder.typicode.com/users https://jsonplaceholder.typicode.com/users/3 https://jsonplaceholder.typicode.com/users/3/posts https://jsonplaceholder.typicode.com/posts?userId=3&_limit=2 https://jsonplaceholder.typicode.com/users/9999
Az utolsónál mi a státuszkód (F12 → Network)? Miért éppen az?
Fejlécek vizsgálata. F12 → Network fülön nyiss meg egy
tetszőleges oldalt, kattints az első kérésre, és írd ki:
Content-Type fejlécét;Cache-Control fejléc, és mit mond;curl. Küldj el parancssorból egy GET és egy
POST kérést a jsonplaceholder.
API-nak! Mentsd el a parancsokat és a kimenetet. (A -i kapcsolóval a fejlécek
is látszanak.)
Kérésnapló. Válassz egy webshopot, nyisd meg a DevTools Network fülét, és szűrj a
Fetch/XHR típusra. Tegyél valamit a kosárba, és nézd meg: milyen kérés indult
(metódus, URL, státuszkód), és mit küldött a törzsében? Írd le, mit gondolsz, mit csinál ez a végpont a
szerveren.
Tíz kérdés. Válassz, és azonnal megtudod, jó volt-e — magyarázattal.
GET,
POST, PUT, PATCH,
DELETE), a státuszkód azt, mi lett az eredmény
(2xx / 4xx / 5xx).GET biztonságos (nem változtat); a
GET, PUT, DELETE
idempotens, a POST nem.| Fogalom | Jelentés |
|---|---|
| HTTP HyperText Transfer Protocol | A web kérés–válasz protokollja |
| Kérés / válasz | Kezdősor + fejlécek + üres sor + (törzs) |
| Metódus (ige) | Mit akarunk tenni: GET, POST, PUT, PATCH, DELETE |
| Státuszkód | Háromjegyű eredményjelző: 2xx siker, 4xx kliens-, 5xx szerverhiba |
| Fejléc (header) | Kulcs–érték metaadat a kérésről vagy válaszról |
| Törzs (body) | A tényleges adat, jellemzően JSON |
| URI / végpont Uniform Resource Identifier | Az erőforrás címe, illetve az API egy elérési pontja |
| Erőforrás | A REST-ben kezelt „dolog” (termék, rendelés, felhasználó) |
| Reprezentáció | Az erőforrás egy formába öntött változata (JSON) |
| REST Representational State Transfer | Erőforrás-orientált architekturális stílus HTTP-re építve |
| Stateless | A szerver nem tárol munkamenetet a kérések között |
| Idempotens | Többszöri végrehajtás ugyanazt az állapotot eredményezi |
| Biztonságos (safe) | A kérés nem változtat állapotot (GET, HEAD) |
| CRUD | Create, Read, Update, Delete |
| JSON JavaScript Object Notation | Szöveges adatcsere-formátum |
| CORS Cross-Origin Resource Sharing | Böngészőbeli szabály a más eredetű kérésekre |
| Bearer token | Az Authorization fejlécben küldött hitelesítő jegy (pl. JWT) |
| Rate limiting | Kérésszám-korlátozás; túllépéskor 429 |
| OpenAPI / Swagger | Géppel olvasható API-dokumentáció |
| HATEOAS Hypermedia As The Engine Of Application State | A válasz linkeket ad a lehetséges következő lépésekhez |