GraphQL és RPC: két másik API-szemlélet
Célok
A lecke végére meg tudod mondani, miben tér el a GraphQL és az RPC a REST erőforrásmodelljétől, le tudsz olvasni egy egyszerű GraphQL-lekérdezést és egy JSON-RPC-hívást, és érted, hogy a három stílus közti választás a feladat függvénye.
Miért kell más szemlélet is?
Nem minden adatcsere azonosítható erőforrások köré szerveződik. Egy mobilkijelző a kurzus címét, oktatóját és az órarendi elemeit egyszerre szeretné megmutatni. Erőforrásokra szervezett API-nál ez több kérés lehet, vagy a szerver olyan reprezentációt ad, amely mindent tartalmaz (akár feleslegesen sokat is). Más helyzetben a kliens nem adatot kér, hanem műveletet: „indítsd el a jelentkezést”. A GraphQL az első, az RPC a második igényre ad természetes választ. Nem a REST „fejlettebb” vagy „elavult” változatai, hanem más hangsúlyú minták.
flowchart LR
C[Kliens igénye] --> R[REST: erőforrás és reprezentáció]
C --> G[GraphQL: mezőválasztás a sémában]
C --> P[RPC: megnevezett művelet]
GraphQL: a kívánt mezők megnevezése
A GraphQL szolgáltatás sémája leírja, milyen típusok és mezők kérhetők. A kliens lekérdezése kiválasztja a szükséges mezőket, és a válasz pontosan ezt a szerkezetet követi. A GraphQL saját leírása szerint a kliens pontosan azt az adatot kérheti, amire szüksége van, egy erős típusrendszeren keresztül.
Egy kipróbált példa (a graphql JavaScript-könyvtár 17.0.2-es verziójával, memóriabeli adattal):
type Oktato { nev: String! }
type Kurzus { id: ID!, cim: String!, ferohely: Int!, oktato: Oktato }
type Query { kurzus(id: ID!): Kurzus }
A séma szerint van egy kurzus lekérdezés, amelynek id kell. Három kérés és a tényleges válasz:
{ kurzus(id: "webprog") { cim oktato { nev } } }
-> {"data":{"kurzus":{"cim":"Webprogramozás 1.","oktato":{"nev":"Minta Péter"}}}}
{ kurzus(id: "webprog") { cim ferohely } }
-> {"data":{"kurzus":{"cim":"Webprogramozás 1.","ferohely":40}}}
{ kurzus(id: "webprog") { cim szinpad } }
-> {"errors":[{"message":"Cannot query field \"szinpad\" on type \"Kurzus\".", ...}]}
- Az első és a második kérés ugyanarra az erőforrásra vonatkozik, de más mezőket kér, és csak azokat kapja meg.
- A harmadik kérés olyan mezőt kér, ami nincs a sémában: a szerver hibát ad, mielőtt bármit végrehajtana. A séma tehát a szerződés része: a kliens csak a támogatott mezőket kérheti.
A GraphQL nem azt jelenti, hogy a kliens közvetlenül az adatbázisban futtat tetszőleges lekérdezést: a szerver ellenőrzi és végrehajtja a kérést, saját szabályai szerint. A mezőválasztás akkor segíthet, ha sokféle kliens eltérő adatigénnyel dolgozik. Másfelől a séma, a jogosultság, a teljesítmény és a hibakezelés tervezést igényel. Az egyetlen végpontból érkező válasz nem automatikusan gyorsabb vagy egyszerűbb minden REST-erőforrásnál.
RPC: műveletek a középpontban
Az RPC (Remote Procedure Call, távoli eljáráshívás) azt a szemléletet emeli ki, hogy a kliens egy távoli, névvel jelölt műveletet kér. A jelentkezesInditasa fogalmilag művelet, nem egy erőforrás reprezentációjának lekérése. Az RPC lehet HTTP-n működő webes API, de maga az elv nem kötődik egyetlen adatformátumhoz vagy protokollhoz.
A JSON-RPC 2.0 egy egyszerű, nyilvános szabvány erre: a kérés tartalmazza a jsonrpc verziót, a method nevét, a params paramétereket és az id azonosítót; a válasz vagy result, vagy error mezőt hordoz, ugyanazzal az id-val. Kipróbálva (a kipróbáló szerver egyetlen műveletet ismer):
-> {"jsonrpc":"2.0","method":"jelentkezesInditasa","params":{"hallgato":"h42","kurzus":"webprog"},"id":1}
<- {"jsonrpc":"2.0","result":{"id":1,"ujLetrejott":true},"id":1}
-> (ugyanaz a hívás újra, id: 2)
<- {"jsonrpc":"2.0","result":{"id":1,"ujLetrejott":false},"id":2}
-> {"jsonrpc":"2.0","method":"mindentTorol","id":3}
<- {"jsonrpc":"2.0","error":{"code":-32601,"message":"Method not found"},"id":3}
Három megfigyelés:
- Az első hívás létrehozta a jelentkezést, a második hívás ugyanezzel a hallgatóval és kurzussal nem hozott létre újat: a szerver felismerte, hogy már létezik. Ez a védekezés a duplikált jelentkezés ellen; az RPC nem mentesít az alól, hogy a szerver az ismételt hívást kezelje (2.3).
- A válasz az
id alapján párosítható a kéréshez.
- Az ismeretlen művelet hibát kap: a JSON-RPC szabvány szerint a
-32601 kód jelentése „Method not found”.
(A JSON-RPC-ben a hiba a válasz törzsében van; a HTTP-státuszkód ettől függetlenül lehet 200. Ez eltér a REST-től, ahol a státuszkód közvetlenül jelzi az eredményt.)
Hogyan hasonlítsuk össze őket?
|
REST |
GraphQL |
RPC |
| Kiindulópont |
erőforrás és HTTP-művelet |
séma és mezőválasztás |
megnevezett művelet |
| Mit kér a kliens? |
egy erőforrás reprezentációját |
pontosan megnevezett mezőket |
egy művelet végrehajtását |
| Hol van a szerződés? |
végpontok, metódusok, státuszkódok |
a séma |
a műveletek és paramétereik |
| Jó választás, ha... |
erőforrásokra jól leképezhető a feladat |
sokféle kliens eltérő adatigénnyel dolgozik |
a feladat célzott művelet |
Valós rendszerek vegyes megoldásokat is alkalmaznak. Egy könyvtári katalógus jól illik az erőforrásos modellhez, egy sokféle felületen megjelenő összetett adat GraphQL-lel is jól kezelhető, egy célzott alkalmazási művelet pedig RPC-ként lehet világos. A technológia nevénél fontosabb, hogy a szerződés érthető és a kliens igényéhez illő legyen.
Végigvezetett példa: a Kurzuspont mobilkijelzője
A mobilkijelzőn a kurzus címe, az oktatója és a szabad helyek száma kell, az órarend viszont nem.
- REST:
GET /api/kurzusok/webprog a teljes kurzusobjektumot adja, az oktató külön kérés lehet, vagy a szerver beágyazza. Egyszerű, gyorsítótárazható.
- GraphQL: a mobil csak a három kért mezőt kapja, egyetlen kérésben. A séma jól dokumentált, de a szervernek kezelnie kell a lekérdezések bonyolultságát.
- RPC:
kurzusAttekintes művelet egy előre összeállított nézetet ad. Nagyon célzott, de a művelet és a kliens szorosabban kötődik.
A Kurzuspont a kurzusadatokat REST-tel, a jelentkezést pedig akár célzott művelettel is kiszolgálhatja. A választás a feladat és a szerződés minőségének kérdése.
Gyakori tévhitek
| Állítás |
Pontosítás |
| „GraphQL-ben a kliens közvetlenül az adatbázist olvassa.” |
A kliens a szolgáltatás sémáján keresztül kér adatot; a szerver ellenőrzi. |
| „Az RPC egy konkrét protokoll neve.” |
Műveletközpontú szemlélet; a JSON-RPC egy konkrét szabvány. |
| „A GraphQL mindig egyetlen gyors kérés.” |
A szerver munkája és az adatigény összetettsége továbbra is számít. |
| „Egyetlen stílus minden API-nál helyes.” |
A feladat és a szerződés minősége dönt. |
| „RPC-nél nem kell az ismétlésre gondolni.” |
A hívás megismétlése itt is kezelendő (idempotencia, 2.3). |
Röviden
- A GraphQL sémából mezőket választ, a válasz a kérés szerkezetét követi.
- Az RPC névvel jelölt műveletet hív; a JSON-RPC egy egyszerű, szabványos forma.
- A séma, illetve a műveletek leírása a szerződés.
- A választás a kliens igényétől és a szerződés érthetőségétől függ, nem divattól.
Ellenőrző kérdések
- Mit nyer a kliens azzal, hogy a GraphQL-ben a mezőket maga választja ki?
- Mi történik, ha a lekérdezés olyan mezőt kér, ami nincs a sémában?
- Miért kell az RPC-ben is gondolni az ismételt hívásra?
- Mikor választanál RPC-t REST helyett?
Tanulási források
GraphQL és RPC: két másik API-szemlélet
Célok
A lecke végére meg tudod mondani, miben tér el a GraphQL és az RPC a REST erőforrásmodelljétől, le tudsz olvasni egy egyszerű GraphQL-lekérdezést és egy JSON-RPC-hívást, és érted, hogy a három stílus közti választás a feladat függvénye.
Miért kell más szemlélet is?
Nem minden adatcsere azonosítható erőforrások köré szerveződik. Egy mobilkijelző a kurzus címét, oktatóját és az órarendi elemeit egyszerre szeretné megmutatni. Erőforrásokra szervezett API-nál ez több kérés lehet, vagy a szerver olyan reprezentációt ad, amely mindent tartalmaz (akár feleslegesen sokat is). Más helyzetben a kliens nem adatot kér, hanem műveletet: „indítsd el a jelentkezést”. A GraphQL az első, az RPC a második igényre ad természetes választ. Nem a REST „fejlettebb” vagy „elavult” változatai, hanem más hangsúlyú minták.
flowchart LR C[Kliens igénye] --> R[REST: erőforrás és reprezentáció] C --> G[GraphQL: mezőválasztás a sémában] C --> P[RPC: megnevezett művelet]GraphQL: a kívánt mezők megnevezése
A GraphQL szolgáltatás sémája leírja, milyen típusok és mezők kérhetők. A kliens lekérdezése kiválasztja a szükséges mezőket, és a válasz pontosan ezt a szerkezetet követi. A GraphQL saját leírása szerint a kliens pontosan azt az adatot kérheti, amire szüksége van, egy erős típusrendszeren keresztül.
Egy kipróbált példa (a
graphqlJavaScript-könyvtár 17.0.2-es verziójával, memóriabeli adattal):type Oktato { nev: String! } type Kurzus { id: ID!, cim: String!, ferohely: Int!, oktato: Oktato } type Query { kurzus(id: ID!): Kurzus }A séma szerint van egy
kurzuslekérdezés, amelynekidkell. Három kérés és a tényleges válasz:A GraphQL nem azt jelenti, hogy a kliens közvetlenül az adatbázisban futtat tetszőleges lekérdezést: a szerver ellenőrzi és végrehajtja a kérést, saját szabályai szerint. A mezőválasztás akkor segíthet, ha sokféle kliens eltérő adatigénnyel dolgozik. Másfelől a séma, a jogosultság, a teljesítmény és a hibakezelés tervezést igényel. Az egyetlen végpontból érkező válasz nem automatikusan gyorsabb vagy egyszerűbb minden REST-erőforrásnál.
RPC: műveletek a középpontban
Az RPC (Remote Procedure Call, távoli eljáráshívás) azt a szemléletet emeli ki, hogy a kliens egy távoli, névvel jelölt műveletet kér. A
jelentkezesInditasafogalmilag művelet, nem egy erőforrás reprezentációjának lekérése. Az RPC lehet HTTP-n működő webes API, de maga az elv nem kötődik egyetlen adatformátumhoz vagy protokollhoz.A JSON-RPC 2.0 egy egyszerű, nyilvános szabvány erre: a kérés tartalmazza a
jsonrpcverziót, amethodnevét, aparamsparamétereket és azidazonosítót; a válasz vagyresult, vagyerrormezőt hordoz, ugyanazzal azid-val. Kipróbálva (a kipróbáló szerver egyetlen műveletet ismer):Három megfigyelés:
idalapján párosítható a kéréshez.-32601kód jelentése „Method not found”.(A JSON-RPC-ben a hiba a válasz törzsében van; a HTTP-státuszkód ettől függetlenül lehet
200. Ez eltér a REST-től, ahol a státuszkód közvetlenül jelzi az eredményt.)Hogyan hasonlítsuk össze őket?
Valós rendszerek vegyes megoldásokat is alkalmaznak. Egy könyvtári katalógus jól illik az erőforrásos modellhez, egy sokféle felületen megjelenő összetett adat GraphQL-lel is jól kezelhető, egy célzott alkalmazási művelet pedig RPC-ként lehet világos. A technológia nevénél fontosabb, hogy a szerződés érthető és a kliens igényéhez illő legyen.
Végigvezetett példa: a Kurzuspont mobilkijelzője
A mobilkijelzőn a kurzus címe, az oktatója és a szabad helyek száma kell, az órarend viszont nem.
GET /api/kurzusok/webproga teljes kurzusobjektumot adja, az oktató külön kérés lehet, vagy a szerver beágyazza. Egyszerű, gyorsítótárazható.kurzusAttekintesművelet egy előre összeállított nézetet ad. Nagyon célzott, de a művelet és a kliens szorosabban kötődik.A Kurzuspont a kurzusadatokat REST-tel, a jelentkezést pedig akár célzott művelettel is kiszolgálhatja. A választás a feladat és a szerződés minőségének kérdése.
Gyakori tévhitek
Röviden
Ellenőrző kérdések
Tanulási források