Skip to content
Language:hu Author:Laborci Gergely
web-api

REST: erőforrások és HTTP-műveletek

Célok

A lecke végére meg tudod mondani, mit jelent a REST szemlélete, tudsz erőforrás-alapú végpontokat és HTTP-műveleteket hozzárendelni egy feladathoz, és el tudod különíteni a REST-et attól, hogy „az API JSON-t ad”.

Miért kell az API-hoz tervezési szemlélet?

Ha minden API-tervező kitalálná a saját logikáját (egyiknél /getKurzus?id=3, másiknál /kurzus/lekeres/3), a fejlesztőknek minden szolgáltatást külön kellene megtanulniuk. A REST (Representational State Transfer) olyan architekturális megközelítés, amely a webes erőforrásokra és a HTTP szabályos használatára épít: a cím azonosít, a metódus a szándékot jelzi, a státuszkód az eredményt. Aki ismeri a HTTP-t (2. fejezet), egy REST-szerű API-ban nagyrészt otthon van. Az MDN szerint a REST olyan tervezési megszorítások halmaza, amelyek hatékony, megbízható és skálázható elosztott rendszereket céloznak.

Kurzusok mint erőforrások

Az erőforrás egy azonosítható dolog. A Kurzuspontban a kurzusok gyűjteménye és egy konkrét kurzus külön erőforrás: /api/kurzusok a gyűjtemény, /api/kurzusok/webprog egy kurzus. A konkrét címek tervezési döntések; a lényeg, hogy az azonosítók követhető jelentéssel bírjanak.

flowchart LR
    G["/api/kurzusok: gyűjtemény"] --> K["/api/kurzusok/webprog: egy kurzus"]
    K --> R["JSON vagy más reprezentáció"]

Az erőforrást a szerver különböző reprezentációban (például JSON) adja. A kliens a reprezentációval dolgozik, nem egy távoli adatbázistáblát nyit meg.

A HTTP-metódusok jelentése

A metódusok a 2.3 lecke szerinti jelentésükkel szerepelnek: a GET olvas, a POST létrehoz vagy feldolgoz, a PATCH részben módosít, a PUT teljesen cserél, a DELETE töröl. A Kurzuspont kipróbáló API-jának valódi válaszai (lerövidítve):

Kérés Cél Válasz
GET /api/kurzusok/webprog egy kurzus lekérése 200 OK + JSON
GET /api/kurzusok/nincs nem létező kurzus 404 Not Found + {"hiba":{"kod":"nincs_ilyen_kurzus",...}}
POST /api/jelentkezesek {"kurzus":"webprog"} jelentkezés létrehozása 201 Created, Location: /api/jelentkezesek/1
POST /api/jelentkezesek {"kurzus":"adatbazisok"} betelt kurzus 409 Conflict + {"hiba":{"kod":"betelt",...}}
POST /api/jelentkezesek (nem JSON törzs) rossz típus 415 Unsupported Media Type
PATCH /api/kurzusok/webprog {"cim":"..."} cím módosítása 200 OK + az új állapot
DELETE /api/kurzusok/adatbazisok kurzus törlése 204 No Content
DELETE ugyanarra újra már törölt 404 Not Found

Egy kérés és a válasz teljes alakja:

$ curl -i -X POST http://localhost:8081/api/jelentkezesek \
    -H 'Content-Type: application/json' -d '{"kurzus":"webprog"}'
HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
Location: /api/jelentkezesek/1

{"id":1,"kurzus":"webprog"}

A 201 jelzi, hogy új erőforrás jött létre, a Location fejléc pedig megadja a címét. A betelt kurzusra 409 Conflict válaszol: a kérés formailag helyes, de ütközik az erőforrás állapotával (2.4).

A táblázat egy lehetséges szerződés, nem valódi egyetemi API. Nem minden felhasználó jogosult létrehozásra vagy törlésre: a metódus és a jogosultság külön kérdés, ahogy a technikai helyesség és az üzleti szabályok teljesülése is.

Állapotmentesség és következetes hibák

A REST egyik fontos megszorítása az állapotmentes kliens–szerver kommunikáció: minden kérés önmagában hordozza az értelmezéséhez szükséges információt, és a szerver nem támaszkodik arra, hogy a kliens előző kérésének alkalmazásszintű beszélgetésállapota nála maradt. Ez nem tiltja, hogy a szerver adatot tároljon, és nem azt jelenti, hogy a felhasználónak ne lehetne bejelentkezése. A bejelentkezett állapotot a kérésekhez csatolt azonosítóval oldják meg (7. fejezet).

A hibákhoz is következetes hibaformát érdemes adni. A fenti példában minden hiba {"hiba":{"kod":...,"uzenet":...}} alakú, így a kliens nem csak egy számot, hanem feldolgozható okot kap: a kod a gépnek szól, az uzenet az embernek. A hibaválasz a szerződés része (5.6).

Mi nem következik a REST-ből?

Más API-stílus is lehet indokolt. Ha a kliens sokféle összekapcsolt adatból akar pontos mezőket választani, vagy névvel jelölt távoli műveleteket hív, a következő lecke eltérő megközelítéseket mutat be.

Végigvezetett példa: a Kurzuspont végpontjai

Feladat Végpont Metódus Sikeres válasz
Kurzuslista /api/kurzusok GET 200
Egy kurzus /api/kurzusok/{id} GET 200
Jelentkezés /api/jelentkezesek POST 201
Lemondás /api/jelentkezesek/{id} DELETE 204

Az „egy kurzus” és a „jelentkezés” külön erőforrás: a jelentkezésnek saját azonosítója van, ezért lehet külön lemondani. Ha a lemondás ismétlődik, a DELETE idempotens (2.3), így a második hívás veszélytelen. A POST ismétlése viszont ugyanarra a kurzusra két jelentkezést hozhat létre, ha a szerver nem védekezik.

Gyakori tévhitek

Állítás Pontosítás
„REST = JSON.” A JSON csak lehetséges reprezentáció.
„Minden POST létrehozás.” A szerződés más feldolgozást is rendelhet hozzá.
„Állapotmentes = a szerver nem tárol adatot.” A kérések közötti beszélgetésállapotról szól, nem az adatbázis hiányáról.
„Főnévi URL-től minden API REST.” A HTTP-szemantika és a további megszorítások is számítanak.
„A 200 elég minden válaszra.” A pontos státuszkód (201, 204, 404, 409...) információt ad a kliensnek.

Röviden

  • A REST erőforrásokra és a HTTP szabályos használatára épül: a cím azonosít, a metódus a szándékot, a státuszkód az eredményt jelzi.
  • Az erőforrásnak lehet több reprezentációja is (például JSON).
  • Állapotmentes: a kérés önmagában hordoz minden szükséges információt.
  • A hibaformátum a szerződés része.
  • A „JSON-t ad” és a „REST” nem ugyanaz.

Ellenőrző kérdések

  1. Mi a különbség a gyűjtemény és az egyes erőforrás címe között?
  2. Mit jelent a 201 Created és mire jó a Location fejléc?
  3. Miért 409 Conflict a betelt kurzus válasza?
  4. Miért nem elég, ha egy API főnévi URL-eket használ és JSON-t ad, hogy REST legyen?

Tanulási források

Prerequisites (2)

  • HTTP
  • webes API

Teaches (1)

  • REST