Bevezetés a GraphQL-be

1. Áttekintés

A GraphQL egy lekérdezési nyelv, amelyet a Facebook hozott létre azzal a céllal, hogy intuitív és rugalmas szintaxison alapuló ügyfélalkalmazásokat építsen az adatigényeik és interakcióik leírására.

A hagyományos REST hívások egyik elsődleges kihívása az, hogy az ügyfél nem képes egyedi (korlátozott vagy kibővített) adatkészletet kérni. A legtöbb esetben, ha az ügyfél információt kér a szervertől, akkor vagy az összes mezőt megkapja, vagy egyiket sem.

További nehézség a több végpont működése és fenntartása. Ahogy a platform növekszik, következésképpen a szám növekszik. Ezért az ügyfeleknek gyakran kell adatokat kérniük különböző végpontoktól.

A GraphQL kiszolgáló felépítésekor csak egy URL szükséges az összes adat lekéréséhez és mutációjához. Így az ügyfél kérhet egy adatsort egy lekérdezési karaktersorozat elküldésével, amely leírja, hogy mit akar, egy kiszolgálónak.

2. Alapvető GraphQL-nómenklatúra

Vessünk egy pillantást a GraphQL alapvető terminológiájára.

  • Lekérdezés: egy csak olvasható művelet, amelyet egy GraphQL kiszolgálónak kért
  • Mutáció: egy írás-olvasási művelet, amelyet egy GraphQL szerverhez kértek
  • Megoldó: A GraphQL-ben az Megoldó felelős a művelet és a háttéren futó kód feltérképezéséért, amely a kérés kezeléséért felelős. Ez analóg az MVC háttérrel egy RESTFul alkalmazásban
  • Típus: A típus meghatározza a GraphQL szerverről visszaküldhető válaszadatok alakját, beleértve azokat a mezőket is, amelyek élek a másikhoz Típusok
  • Bemenet: mint egy Típus, de meghatározza a GraphQL szerverre küldött bemeneti adatok alakját
  • Skalár: primitív típus, például a Húr, Int, Logikai, Úszóstb
  • Felület: Egy interfész tárolja a mezők nevét és argumentumaikat, így a GraphQL objektumok örökölhetnek belőle, biztosítva bizonyos mezők használatát
  • Séma: A GraphQL-ben a Séma kezeli a lekérdezéseket és a mutációkat, meghatározva, hogy mit szabad végrehajtani a GraphQL szerveren

2.1. Séma betöltése

Kétféle módon tölthetünk be egy sémát a GraphQL szerverre:

  1. a GraphQL Interface Definition Language (IDL) használatával
  2. az egyik támogatott programozási nyelv használatával

Bemutassunk egy példát az IDL használatával:

írja be a következő felhasználót: {firstName: String}

Most egy példa a Java kódot használó séma-meghatározásra:

GraphQLObjectType userType = newObject () .name ("User") .field (newFieldDefinition () .name ("firstName") .type (GraphQLString)) .build ();

3. Interfész meghatározás nyelve

Interface Definition Language (IDL) vagy Schema Definition Language (SDL) a legtömörebb módszer a GraphQL-séma megadására. A szintaxis jól körülhatárolható, és a hivatalos GraphQL specifikáció fogja elfogadni.

Hozzunk létre például egy GraphQL sémát egy Felhasználó számára / E-maileket így lehet megadni:

schema {query: QueryType} enum Nem {MALE FEMALE} típus User {id: String! keresztnév: Húr! vezetéknév: Karakterlánc! createdAt: DateTime! kor: Int! @ alapértelmezett (érték: 0) nem: [Nem]! e-mailek: [Email!]! @relation (név: "E-mailek")} típus: Email {id: String! email: Karakterlánc! alapértelmezett: Int! @ alapértelmezett (érték: 0) felhasználó: Felhasználó @ kapcsolat (név: "E-mailek")}

4. GraphQL-java

A GraphQL-java a specifikáción és a JavaScript referencia implementáción alapuló megvalósítás. Ne feledje, hogy a megfelelő futtatáshoz legalább Java 8 szükséges.

4.1. GraphQL-java kommentárok

A GraphQL emellett lehetővé teszi a Java annotációk használatát a sémadefiníció előállításához anélkül, hogy a hagyományos IDL megközelítés használatával létrehozott összes kazánlap kódot létrehoznák.

4.2. Függőségek

A példánk létrehozásához először kezdjük el importálni a szükséges függőséget, amely a Graphql-java-annotations modulra támaszkodik:

 com.graphql-java graphql-java-annotations 3.0.3 

Az alkalmazásunk beállításának megkönnyítése érdekében egy HTTP könyvtárat is megvalósítunk. A Ratpack alkalmazást fogjuk használni (bár a Vert.x, Spark, Dropwizard, Spring Boot stb. Esetén is megvalósítható).

Importáljuk a Ratpack függőséget is:

 io.ratpack ratpack-core 1.4.6 

4.3. Végrehajtás

Készítsük el a példánkat: egy egyszerű API, amely „CRUDL” -ot (létrehozás, visszakeresés, frissítés, törlés és lista) biztosít a felhasználók számára. Először hozzuk létre a sajátunkat Felhasználó POJO:

@GraphQLName ("user") public class User {@GraphQLField private Long id; @GraphQLField private String név; @GraphQLField privát karakterlánc e-mail; // getterek, beállítók, konstruktorok és segítő módszerek kihagyva}

Ebben a POJO-ban láthatjuk a @GraphQLName („felhasználó”) annotáció, annak jelzésére, hogy ezt az osztályt a GraphQL hozzárendeli minden egyes mezőhöz, amelyhez annotált @GraphQLField.

Ezután létrehozzuk a UserHandler osztály. Ez az osztály a kiválasztott HTTP csatlakozó könyvtárból (esetünkben Ratpack) örököl egy kezelő metódust, amely kezeli és meghívja a GraphQL Megoldó funkció. Így a kérelem (JSON hasznos terhelések) átirányítása a megfelelő lekérdezési vagy mutációs műveletre:

A @Orride public void handle (Context context) kivételt dob ​​a {context.parse (Map.class) .then (hasznos teher -> {Térkép paraméterek = (Térkép) payload.get ("paraméterek"); ExecutionResult végrehajtási eredmény = graphql .execute (hasznos terhelés .get (SchemaUtils.QUERY) .toString (), null, ez, paraméterek); Térkép eredménye = new LinkedHashMap (); if (végrehajtásRezult.getErrors (). getData ());} else {result.put (SchemaUtils.ERRORS, végrehajtásiRezult.getErrors ()); LOGGER.warning ("Hibák:" + végrehajtásRezult.getErrors ());} context.render (json (eredmény)); }); }

Most a lekérdezési műveleteket támogató osztály, azaz UserQuery. Mint már említettük, az összes módszert, amely adatokat keres a szerverről az ügyfélre, ez az osztály kezeli:

@GraphQLName ("query") public class UserQuery {@GraphQLField public static User retrieveUser (DataFetchingEnvironment env, @NotNull @GraphQLName ("id") String id) {// return user} @GraphQLField public static List listUsers (DataFetchingEnvironmentv // visszatér a felhasználók listájához}}

Hasonlóan UserQuery, most alkotunk UserMutation, amely kezeli az összes olyan műveletet, amely megváltoztatni kívánja a szerver oldalon tárolt bizonyos adatokat:

@GraphQLName ("mutáció") public class UserMutation {@GraphQLField public static User createUser (DataFetchingEnvironment env, @NotNull @GraphQLName ("name") String name, @NotNull @GraphQLName ("email") String email) {// user create információ}}

Érdemes észrevenni a feljegyzéseket mindkettőben UserQuery és UserMutation osztályok: @GraphQLName („lekérdezés”) és @GraphQLName („mutáció”). Ezeket az annotációkat a lekérdezés és a mutációs műveletek meghatározására használják.

Ha a GraphQL-java kiszolgáló képes futtatni a lekérdezési és mutációs műveleteket, akkor a következő JSON hasznos terhelésekkel tesztelhetjük az ügyfél kérését a szerverrel szemben:

  • A CREATE művelethez:
{"query": "mutáció ($ name: String! $ email: String!) {createUser (név: $ name email: $ email) {id name email age}}", "paraméterek": {"name": " John "," email ":" [email protected] "}} 

A szerver válasza erre a műveletre:

{"data": {"createUser": {"id": 1, "name": "John", "email": "[email protected]"}}}
  • A RETRIEVE művelethez:
{"query": "lekérdezés ($ id: String!) {retrieveUser (id: $ id) {név email}}", "paraméterek": {"id": 1}}

A szerver válasza erre a műveletre:

{"data": {"retrieveUser": {"name": "John", "email": "[email protected]"}}}

A GraphQL olyan szolgáltatásokat kínál, amelyekkel az ügyfél testreszabhatja a választ. Tehát a példaként használt legutóbbi RETRIEVE műveletben a név és az e-mail visszaadása helyett például csak az e-mailt adhatjuk vissza:

{"query": "lekérdezés ($ id: String!) {retrieveUser (id: $ id) {email}}", "paraméterek": {"id": 1}}

Tehát a GraphQL szerverről a visszatérő információk csak a kért adatokat adják vissza:

{"data": {"retrieveUser": {"email": "[email protected]"}}}

5. Következtetés

A GraphQL egy egyszerű és meglehetősen vonzó módszer a kliens / szerver közötti összetettség minimalizálására, mint a REST API-k alternatív megközelítése.

Mint mindig, a példa elérhető a GitHub adattárunkban.