Ce este GraphQL?

Prezentare generală

GraphQL este un API nou și interesant pentru interogări și manipulări ad-hoc. Este extrem de flexibil și oferă multe beneficii. Este deosebit de potrivit pentru expunerea datelor organizate ca grafice și arbori. Facebook a dezvoltat GraphQL în 2012 și a deschis-o în 2015. 

A decolat rapid și a devenit una dintre cele mai fierbinți tehnologii. Multe companii inovatoare au adoptat și au utilizat GraphQL în producție. În acest tutorial veți afla: 

  • principiile lui GraphQL
  • cum se compară cu REST
  • cum să proiectezi scheme
  • cum să configurați un server GraphQL
  • cum să implementați interogări și mutații 
  • și câteva subiecte avansate

În cazul în care GraphQL Shine?

GraficQL este cel mai bun atunci când datele dvs. sunt organizate într-o ierarhie sau într-un grafic, iar partea frontală ar dori să acceseze diferite subseturi ale acestei ierarhii sau grafice. Luați în considerare o aplicație care expune NBA. Aveți echipe, jucători, antrenori, campionate și o mulțime de informații despre fiecare. Iată câteva exemple de interogări:

  • Care sunt numele jucătorilor de pe lista actuală a Războinicilor de Stat de Aur?
  • Care sunt numele, înălțimile și vârstele starilor Washington Wizards?
  • Care antrenor activ are cele mai multe campionate?
  • Pentru care echipe și în ce anume antrenorul a câștigat campionatul?
  • Care jucător a câștigat cele mai multe premii MVP?

Am putut veni cu sute de astfel de întrebări. Imaginați-vă că trebuie să proiectați un API pentru a expune toate aceste interogări la capătul frontal și pentru a putea extinde cu ușurință API-ul cu noi tipuri de interogări pe măsură ce utilizatorii sau managerul de produs vin cu noi lucruri interesante de interogare.

Acest lucru nu este banal. GraphQL a fost conceput pentru a rezolva această problemă exactă și cu un singur punct final API oferă o putere enormă, așa cum veți vedea în curând.

GraphQL vs. REST

Înainte de a scufunda în nuci și bolțuri de GraphQL, să o comparăm cu REST, care este în prezent cel mai popular tip de API web.

REST urmează un model orientat spre resurse. În cazul în care resursele noastre sunt jucători, antrenori și echipe, atunci probabil vor exista puncte finale precum:

  • / jucători 
  • / jucători / 
  • / antrenori
  • / antrenori / 
  • / echipe
  • / echipe /

Adesea, punctele finale fără id întoarce doar o listă de ID-uri, iar punctele finale cu id-ul returnează informațiile complete despre o singură resursă. Desigur, puteți proiecta API-ul dvs. în alte moduri (de exemplu, punctul final / jucători poate returna și numele fiecărui jucător sau toate informațiile despre fiecare jucător).

Problema cu această abordare într-un mediu dinamic este faptul că sunteți fie subtotal (de exemplu, obțineți doar ID-urile și aveți nevoie de mai multe informații), fie că vă preocupați (de ex. Obțineți informații complete despre fiecare jucător atunci când sunteți doar interesat de nume). 

Acestea sunt probleme grele. Când descărcați mai puțin de 100 de ID-uri, va trebui să efectuați 100 de apeluri API separate pentru a obține informațiile despre fiecare jucător. Atunci când prelungiți, veți pierde o mulțime de timp de back-end și lățime de bandă de rețea pregătirea și transferul unei mulțimi de date care nu sunt necesare.

Există modalități de abordare cu REST. Aveți posibilitatea să proiectați o mulțime de obiective personalizate, fiecare returnând exact datele de care aveți nevoie. Această soluție nu este scalabilă. Este greu să păstrați API consistent. E greu să o dezvolți. Este greu de documentat și de utilizat. Este greu să o mențineți atunci când există o mulțime de suprapuneri între aceste obiective personalizate.

Luați în considerare aceste obiective suplimentare:

  • / jucători / nume
  • / jucători / names_and_championships
  • / echipa / startere

O altă abordare este de a păstra un număr mic de obiective generice, dar oferă o mulțime de parametri de interogare. Această soluție evită problema numeroaselor puncte finale, dar este împotriva cererii modelului REST și, de asemenea, este dificil să se dezvolte și să se mențină în mod consecvent.

Ați putea spune că GraphQL a luat această abordare la limită. Nu se gîndește în termeni de resurse bine definite, ci în termeni de subgrafuri ale întregului domeniu.

Sistemul de tip GraphQL

GraphQL modelează domeniul utilizând un sistem tip care constă din tipuri și atribute. Fiecare atribut are un tip. Tipul de atribut poate fi unul dintre tipurile de bază pe care GraphQL le oferă ca ID, String și Boolean sau un tip definit de utilizator. Nodurile graficului sunt tipurile definite de utilizator, iar marginile sunt atributele care au tipuri definite de utilizator. 

De exemplu, dacă un tip "Player" are un atribut "team" cu tipul "Team", înseamnă că există o margine între fiecare nod de jucător și un nod de echipă. Toate tipurile sunt definite într-o schemă care descrie modelul de obiect de domeniu GraphQL. 

Iată o schemă foarte simplificată pentru domeniul NBA. Jucătorul are un nume, o echipă cu care este cel mai asociat (da, știu că jucătorii se mișcă uneori de la o echipă la alta) și numărul de campionate pe care le-a câștigat. 

Echipa are un nume, o serie de jucători și numărul de campionate pe care echipa le-a câștigat.

tip Player id: ID: String! Echipa: Echipa! campionatCount: Integer!  tastați Echipa id: ID: String! jucători: [Jucător!]! campionatCount: Integer!  

Există, de asemenea, puncte de intrare predefinite. Acestea sunt Query, Mutation și Subscription. Partea frontală comunică cu capătul din spate prin punctele de intrare și le personalizează pentru nevoile sale.

Iată o interogare care întoarce pur și simplu toți jucătorii:

introduceți Interogare allPlayers: [Player!]! 

Punctul de exclamare înseamnă că valoarea nu poate fi nulă. În cazul allPlayers interogare, poate returna o listă goală, dar nu și null. De asemenea, înseamnă că nu poate exista niciun jucător nul în listă (deoarece conține Player!).

Configurarea unui server GraphQL

Aici este un server GraphQL complet bazat pe node-express. Dispune de un magazin de date stocat în memorie. În mod normal, datele se vor afla într-o bază de date sau vor fi preluate de la un alt serviciu. Datele sunt definite aici (scuzați-vă în prealabil dacă echipa sau jucătorul preferat nu a reușit):

lăsați data = "allPlayers": "1": "id": "1", "nume": "Stephen Curry", "championshipCount": 2; "id": "2", "nume": "Michael Jordan", "campionatCount": 6, "teamId": "1", "3": "id"; "Scottie Pippen", "campionatCount": 6, "teamId": "1", "4": "id": "4", "name": Magic Johnson, : "2", "5": "id": "5", "nume": "Kobe Bryant", "championshipCount" id ":" 6 "," nume ":" Kevin Durant "," campionatCount ": 1," teamId ":" 3 ", allTeams: 1" "nume": "Chicago Bulls", "championshipCount": 6, "jucători": [], "2": "id": "2", "nume": "Los Angeles Lakers", "championshipCount": 16, "jucători": ["id": "3", "nume": "Golden State Warriors", "championshipCount": 5, "jucători": [] 

Bibliotecile pe care le folosesc sunt:

const expres = necesită ("expres"); const graphqlHTTP = necesită ('express-graphql'); const app = express (); const buildSchema = necesită ('graphql'); const _ = necesită ('lodash / core');

Acesta este codul pentru a construi schema. Rețineți că am adăugat câteva variabile la allPlayers root query.

schema = buildSchema (tipul de jucator id: ID: String! campionatCount: Int! team: Team! tip Echipa id: ID: String! championshipCount: Int! (offset: Int = 0, limită: Int = -1): [Jucătorul!]! 

Aici vine partea cheie: conectarea interogărilor și furnizarea efectivă a datelor. rootValue obiect poate conține mai multe rădăcini. 

Aici, există doar allPlayers. Extrage offsetul și limitează argumentele, taie datele tuturor jucătorilor și apoi stabilește echipa pe fiecare jucător pe baza ID-ului echipei. Acest lucru face ca fiecare jucător să fie un obiect imbricat.

root = allPlayers: (args) => offset = args ['offset'] limita = args ['limit'] r = _.values ​​(data ["allPlayers" 1) r = r.slice (0, Math.min (limita, lungimea)) _.forEach (r, (x) => data.allPlayers [x.id] .team = x.teamId]) returnează r, 

În cele din urmă, iată graphql punct final, trecerea schemei și a obiectului valoare rădăcină:

app.use ('/ graphql', graphqlHTTP (schema: schema, rootValue: rootValue, graphiql: true)); app.listen (3000); module.exports = app;

reglaj graphiql la Adevărat ne permite să testați serverul cu o grafică excelentă GraphQL IDE în browser. Mi-a recomandat foarte mult experimentarea cu diferite interogări.

Întrebări ad hoc cu GraphQL

Totul este setat. Să navigăm la http: // localhost: 3000 / graphql și să ne distrăm.

Putem începe simplu, doar cu o listă cu numele jucătorilor:

interogare justNames allPlayers name Ieșire: "data": "allPlayers": name: "Stephen Curry" Pippen ", " nume ":" Magic Johnson ", " nume ":" Kobe Bryant ", " nume ":" Kevin Durant "] 

În regulă. Avem niște superstaruri aici. Fără îndoială. Să mergem la ceva mai fermecător: începând de la offset 4 obțineți 2 jucători. Pentru fiecare jucător, rețineți numele și numărul de campionate pe care le-au câștigat, precum și numele echipei și câte campionate a câștigat echipa.

interogare cu doi jucători allPlayers (offset: 4, limit: 2) nume campionatCount echipa name campionshipCount Ieșire: "date": "allPlayers": ["nume": Kobe Bryant, campionatCount: 5, "echipa": "nume": "Los Angeles Lakers", "championshipCount": 16, "nume": "Kevin Durant", "championshipCount" "Golden State Warriors", "campionatCount": 5] 

Astfel, Kobe Bryant a câștigat cinci campionate cu Lakers, care au câștigat 16 campionate în ansamblu. Kevin Durant a câștigat doar un campionat cu Warriors, care a câștigat cinci campionate totale.

GraphQL Mutations

Magic Johnson a fost cu siguranță un magician în instanță. Dar nu ar fi putut să o facă fără Kareem Abdul-Jabbar. Să adăugăm Kareem în baza noastră de date. Putem defini mutații GraphQL pentru a efectua operații precum adăugarea, actualizarea și eliminarea datelor din graficul nostru.

Mai întâi, să adăugăm un tip de mutație la schemă. Seamănă puțin cu semnătura unei funcții:

tip Mutation createPlayer (nume: String, campionatCount: Int, teamId: String): Player

Apoi, trebuie să o implementăm și să o adăugăm la valoarea rădăcină. Implementarea ia pur și simplu parametrii furnizați de interogare și adaugă un nou obiect la date [ 'allPlayers']. Se asigură, de asemenea, stabilirea corectă a echipei. În cele din urmă, returnează noul player.

 create_layer: (args) => id = (_.values ​​(data ['allPlayers']) lungime + 1) .toString () args ['id'] = '] [args [' teamId ']] date [' allPlayers '] [id] = argumente return date [' allPlayers '] [id],

Pentru a adăuga efectiv Kareem, putem invoca mutația și interogarea jucătorului returnat:

mutare addKareem createPlayer (nume: "Kareem Abdul-Jabbar", campionatCount: 6, teamId: "2") nume campionatCount echipa nume Ieșire: "data": "createPlayer" "Kareem Abdul-Jabbar", "campionatCount": 6, "echipa": "nume": "Los Angeles Lakers" 

Aici este un mic secret întuneric despre mutații ... ele sunt de fapt exact la fel ca întrebările. Puteți modifica datele într-o interogare și puteți doar să returnați datele dintr-o mutație. GraphQL nu va intra în codul dvs. Ambele interogări și mutații pot lua argumente și returnează date. Este mai mult ca zahărul sintactic pentru a face schema ta mai ușor de citit de om.

Subiecte avansate

Abonamente

Abonamentele sunt o altă caracteristică a lui GraphQL. Cu abonamente, clientul se poate abona la evenimente care vor fi concediate ori de câte ori se schimbă starea serverului. Abonamentele au fost introduse într-o etapă ulterioară și sunt implementate de diferite cadre în moduri diferite.

Validare

GraphQL va verifica fiecare interogare sau mutație împotriva schemei. Aceasta este o victorie mare atunci când datele de intrare au o formă complexă. Nu trebuie să scrieți codul de validare enervant și fragil. GraphQL va avea grijă de asta pentru dvs.. 

Schema Introspecție

Puteți examina și interoga schema curentă în sine. Aceasta vă oferă meta-puteri pentru a descoperi dinamic schema. Aici este o interogare care returnează toate numele de tip și descrierea lor:

interogare q __schema tipuri descriere nume

Concluzie

GraphQL este o nouă tehnologie API interesantă, care oferă multe beneficii față de API-urile REST. Există o comunitate vibrantă în spatele ei, ca să nu mai vorbim de Facebook. Eu prezic că va deveni un capăt de capăt în cel mai scurt timp. Incearca. O să-ti placă. 

Cod