Introduksjon til GraphQL

1. Oversikt

GraphQL er et spørrespråk, opprettet av Facebook med det formål å bygge klientapplikasjoner basert på intuitiv og fleksibel syntaks, for å beskrive deres datakrav og interaksjoner.

En av de viktigste utfordringene med tradisjonelle REST-samtaler er manglende evne til klienten å be om et tilpasset (begrenset eller utvidet) datasett. I de fleste tilfeller, når klienten ber om informasjon fra serveren, får den enten alle eller ingen av feltene.

En annen vanskelighetsgrad er å jobbe og opprettholde flere endepunkter. Når en plattform vokser, vil antallet følgelig øke. Derfor må klienter ofte be om data fra forskjellige sluttpunkter.

Når du bygger en GraphQL-server, er det bare nødvendig å ha en URL for all data som hentes og muteres. Dermed kan en klient be om et datasett ved å sende en spørringsstreng, som beskriver hva de vil ha, til en server.

2. Grunnleggende GraphQL-nomenklatur

La oss ta en titt på GraphQLs grunnleggende terminologi.

  • Spørsmål: er en skrivebeskyttet operasjon som er bedt om til en GraphQL-server
  • Mutasjon: er en lese-skrive-operasjon som er bedt om til en GraphQL-server
  • Resolver: I GraphQL, er Resolver er ansvarlig for å kartlegge operasjonen og koden som kjører på backend som er ansvarlig for å håndtere forespørselen. Det er analogt med MVC-backend i en RESTFul-applikasjon
  • Type: EN Type definerer formen på responsdata som kan returneres fra GraphQL-serveren, inkludert felt som er kanter til andre Typer
  • Inngang: som en Type, men definerer formen på inndata som sendes til en GraphQL-server
  • Skalar: er en primitiv Type, som en String, Int, Boolsk, Flyte, etc
  • Grensesnitt: Et grensesnitt vil lagre navnene på feltene og deres argumenter, slik at GraphQL-objekter kan arve fra det, og sikre bruk av spesifikke felt
  • Skjema: I GraphQL administrerer skjemaet spørringer og mutasjoner, og definerer hva som er tillatt å kjøres på GraphQL-serveren

2.1. Skjema lasting

Det er to måter å laste inn et skjema på GraphQL-serveren:

  1. ved å bruke GraphQLs Interface Definition Language (IDL)
  2. ved å bruke et av de støttede programmeringsspråkene

La oss demonstrere et eksempel ved hjelp av IDL:

skriv User {firstName: String}

Nå, et eksempel på skjemadefinisjon ved bruk av Java-kode:

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

3. Definisjonsspråk for grensesnitt

Interface Definition Language (IDL) eller Schema Definition Language (SDL) er den mest kortfattede måten å spesifisere et GraphQL-skjema på. Syntaksen er veldefinert og vil bli vedtatt i den offisielle GraphQL-spesifikasjonen.

La oss for eksempel lage et GraphQL-skjema for en bruker / e-post kan spesifiseres slik:

schema {query: QueryType} enum Gender {MALE FEMALE} type User {id: String! fornavn: String! etternavn: String! createdAt: DateTime! alder: Int! @default (verdi: 0) kjønn: [Kjønn]! e-post: [E-post!]! @relation (name: "Emails")} type E-post {id: String! e-post: String! standard: Int! @default (verdi: 0) bruker: Bruker @relasjon (navn: "E-post")}

4. GrafQLQL-java

GraphQL-java er en implementering basert på spesifikasjonen og JavaScript-referanseimplementeringen. Merk at det krever minst Java 8 for å kjøre ordentlig.

4.1. Kommentarer til GraphQL-java

GraphQL gjør det også mulig å bruke Java-merknader for å generere skjemadefinisjonen uten all kjeleplatekoden opprettet ved bruk av den tradisjonelle IDL-tilnærmingen.

4.2. Avhengigheter

For å lage vårt eksempel, la oss først begynne å importere den nødvendige avhengigheten som er avhengig av Graphql-java-annotations-modulen:

 com.graphql-java graphql-java-merknader 3.0.3 

Vi implementerer også et HTTP-bibliotek for å gjøre installasjonen enklere i applikasjonen vår. Vi skal bruke Ratpack (selv om det også kan implementeres med Vert.x, Spark, Dropwizard, Spring Boot, etc.).

La oss også importere Ratpack-avhengigheten:

 io.ratpack ratpack-core 1.4.6 

4.3. Gjennomføring

La oss lage vårt eksempel: en enkel API som gir en "CRUDL" (Opprett, hent, oppdater, slett og liste) for brukere. La oss først lage vår Bruker POJO:

@GraphQLName ("bruker") offentlig klasse bruker {@GraphQLField privat Lang id; @GraphQLField privat strengnavn; @GraphQLField privat streng-e-post; // utelatere, settere, konstruktører og hjelpemetoder utelatt}

I denne POJO kan vi se @GraphQLName (“bruker”) kommentar, som en indikasjon på at denne klassen er kartlagt av GraphQL sammen med hvert felt merket med @GraphQLField.

Deretter oppretter vi UserHandler klasse. Denne klassen arver fra det valgte HTTP-koblingsbiblioteket (i vårt tilfelle Ratpack) en behandlingsmetode som vil administrere og påkalle GraphQL Resolver trekk. Omdirigering av forespørselen (JSON-nyttelaster) til riktig spørrings- eller mutasjonsoperasjon:

@ Overstyr offentlig tomhåndtak (kontekstkontekst) kaster unntak {context.parse (Map.class). Deretter (nyttelast -> {Kartparametere = (kart) nyttelast.get ("parametere"); Utførelsesresultat utførelse Resultat = grafql. Utfør (nyttelast) .get (SchemaUtils.QUERY) .toString (), null, dette, parametere); Kartresultat = ny LinkedHashMap (); hvis (executingResult.getErrors (). isEmpty ()) {result.put (SchemaUtils.DATA, executResult. getData ());} annet {result.put (SchemaUtils.ERRORS, executResult.getErrors ()); LOGGER.warning ("Feil:" + executionResult.getErrors ());} context.render (json (result)); }); }

Nå, klassen som vil støtte spørringsoperasjonene, dvs. UserQuery. Som nevnt administreres alle metoder som henter data fra serveren til klienten av denne klassen:

@GraphQLName ("spørring") offentlig klasse UserQuery {@GraphQLField offentlig statisk bruker retrieveUser (DataFetchingEnvironment env, @NotNull @GraphQLName ("id") Streng-id) {// returner bruker} @GraphQLField offentlig statisk liste listeBrukere (DataFetchingEnvironment env) { // returliste over brukere}}

På samme måte som UserQuery, nå skaper vi UserMutation, som vil administrere alle operasjonene som har til hensikt å endre noen gitte data lagret på serversiden:

@GraphQLName ("mutasjon") offentlig klasse UserMutation {@GraphQLField offentlig statisk bruker createUser (DataFetchingEnvironment env, @NotNull @GraphQLName ("navn") Strengnavn, @NotNull @GraphQLName ("e-post") Streng-e-post) {// opprett bruker informasjon } }

Det er verdt å legge merke til kommentarene i begge UserQuery og UserMutation klasser: @GraphQLName (“spørring”) og @GraphQLName (“mutasjon”). Disse kommentarene brukes til å definere henholdsvis spørrings- og mutasjonsoperasjonene.

Med GraphQL-java-serveren som kan kjøre spørrings- og mutasjonsoperasjonene, kan vi bruke følgende JSON-nyttelaster for å teste forespørselen fra klienten mot serveren:

  • For CREATE-operasjonen:
{"spørring": "mutasjon ($ name: String! $ email: String!) {createUser (name: $ name email: $ email) {id name email age}}", "parameters": {"name": " John "," email ":" [email protected] "}} 

Som svar fra serveren for denne operasjonen:

{"data": {"createUser": {"id": 1, "name": "John", "email": "[email protected]"}}
  • For RETRIEVE-operasjonen:
{"query": "query ($ id: String!) {retrieveUser (id: $ id) {name email}}", "parameters": {"id": 1}}

Som svar fra serveren for denne operasjonen:

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

GraphQL tilbyr funksjoner klienten kan tilpasse svaret. Så i den siste RETRIEVE-operasjonen som ble brukt som eksempel, i stedet for å returnere navnet og e-posten, kan vi for eksempel bare returnere e-posten:

{"query": "query ($ id: String!) {retrieveUser (id: $ id) {email}}", "parameters": {"id": 1}}

Så, den returnerende informasjonen fra GraphQL-serveren vil bare returnere de forespurte dataene:

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

5. Konklusjon

GraphQL er en enkel og ganske attraktiv måte å minimere kompleksiteten mellom klient / server som en alternativ tilnærming til REST APIer.

Som alltid er eksemplet tilgjengelig på GitHub-depotet vårt.


$config[zx-auto] not found$config[zx-overlay] not found