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:
- ved å bruke GraphQLs Interface Definition Language (IDL)
- 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.