Introduktion til GraphQL

1. Oversigt

GraphQL er et forespørgselssprog oprettet af Facebook med det formål at opbygge klientapplikationer baseret på intuitiv og fleksibel syntaks til beskrivelse af deres datakrav og interaktioner.

En af de primære udfordringer med traditionelle REST-opkald er manglende evne hos klienten til at anmode om et tilpasset (begrænset eller udvidet) datasæt. I de fleste tilfælde, når klienten først har anmodet om oplysninger fra serveren, får den enten alle eller ingen af ​​felterne.

En anden vanskelighed er at arbejde og vedligeholde flere slutpunkter. Når en platform vokser, vil antallet derfor stige. Derfor er klienter ofte nødt til at bede om data fra forskellige slutpunkter.

Når du bygger en GraphQL-server, er det kun nødvendigt at have en URL til al data, der henter og muterer. Således kan en klient anmode om et sæt data ved at sende en forespørgselsstreng, der beskriver, hvad de ønsker, til en server.

2. Grundlæggende GraphQL-nomenklatur

Lad os se på GraphQLs grundlæggende terminologi.

  • Forespørgsel: er en skrivebeskyttet handling, der anmodes om til en GraphQL-server
  • Mutation: er en læs-skriv-operation, der anmodes om til en GraphQL-server
  • Løser: I GraphQL er Opløser er ansvarlig for at kortlægge operationen og koden, der kører på backend, som er ansvarlig for at håndtere anmodningen. Det er analogt med MVC-backend i en RESTFul-applikation
  • Type: EN Type definerer formen på svardata, der kan returneres fra GraphQL-serveren, herunder felter, der er kanter til andre Typer
  • Indgang: som en Type, men definerer formen på inputdata, der sendes til en GraphQL-server
  • Skalar: er en primitiv Type, såsom en Snor, Int, Boolsk, Flyde, etc
  • Interface: En grænseflade gemmer navnene på felterne og deres argumenter, så GraphQL-objekter kan arve fra det, hvilket sikrer brugen af ​​bestemte felter
  • Skema: I GraphQL styrer skemaet forespørgsler og mutationer, der definerer, hvad der må udføres på GraphQL-serveren

2.1. Skemaindlæsning

Der er to måder at indlæse et skema på GraphQL-serveren:

  1. ved hjælp af GraphQL's Interface Definition Language (IDL)
  2. ved hjælp af et af de understøttede programmeringssprog

Lad os demonstrere et eksempel ved hjælp af IDL:

skriv bruger {fornavn: streng}

Nu et eksempel på skemadefinition ved hjælp af Java-kode:

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

3. Interface Definition Sprog

Interface Definition Language (IDL) eller Schema Definition Language (SDL) er den mest kortfattede måde at specificere et GraphQL-skema på. Syntaksen er veldefineret og vil blive vedtaget i den officielle GraphQL Specification.

Lad os for eksempel oprette et GraphQL-skema til en bruger / e-mails kan specificeres som dette:

skema {forespørgsel: QueryType} enum Køn {MALE FEMALE} skriv bruger {id: String! fornavn: String! efternavn: String! createdAt: DateTime! alder: Int! @default (værdi: 0) køn: [Køn]! e-mails: [E-mail!]! @relation (navn: "E-mails")} skriv E-mail {id: String! e-mail: String! standard: Int! @default (værdi: 0) bruger: Bruger @relation (navn: "E-mails")}

4. GrafQLQL-java

GraphQL-java er en implementering baseret på specifikationen og JavaScript-referenceimplementeringen. Bemærk, at det kræver mindst Java 8 at køre korrekt.

4.1. Kommentarer til GraphQL-java

GraphQL gør det også muligt at bruge Java-annoteringer til at generere sin skemadefinition uden al kedelpladekoden oprettet ved brug af den traditionelle IDL-tilgang.

4.2. Afhængigheder

For at skabe vores eksempel, lad os først importere den krævede afhængighed, der er afhængig af Graphql-java-annotations-modulet:

 com.graphql-java graphql-java-annotationer 3.0.3 

Vi implementerer også et HTTP-bibliotek for at lette opsætningen i vores applikation. Vi skal bruge Ratpack (selvom det også kunne implementeres med Vert.x, Spark, Dropwizard, Spring Boot osv.).

Lad os også importere Ratpack-afhængigheden:

 io.ratpack ratpack-core 1.4.6 

4.3. Implementering

Lad os oprette vores eksempel: en simpel API, der giver en "CRUDL" (Opret, Hent, Opdater, Slet og Liste) til brugere. Lad os først oprette vores Bruger POJO:

@GraphQLName ("bruger") offentlig klasse bruger {@GraphQLField privat Lang id; @GraphQLField privat strengnavn; @GraphQLField privat streng-mail; // getters, settere, konstruktører og hjælpemetoder udeladt}

I denne POJO kan vi se @GraphQLName (“bruger”) annotation, som en indikation af, at denne klasse kortlægges af GraphQL sammen med hvert felt, der er kommenteret med @GraphQLField.

Derefter opretter vi UserHandler klasse. Denne klasse arver fra det valgte HTTP-stikbibliotek (i vores tilfælde Ratpack) en behandlingsmetode, der styrer og påberåber GraphQL'erne Opløser funktion. Omdirigering af anmodningen (JSON-nyttelast) til den korrekte forespørgsel eller mutationshandling:

@ Overstyr offentlig tomrumshåndtag (kontekstkontekst) kaster undtagelse {kontekst.parse (Map.class). Derefter (nyttelast -> {kortparametre = (kort) nyttelast.get ("parametre"); udførelsesresultat udførelsesresultat = grafql. Udfør (nyttelast) .get (SchemaUtils.QUERY) .toString (), null, dette, parametre); Map result = new LinkedHashMap (); if (executionResult.getErrors (). isEmpty ()) {result.put (SchemaUtils.DATA, executionResult. getData ());} ellers {result.put (SchemaUtils.ERRORS, executionResult.getErrors ()); LOGGER.warning ("Fejl:" + executResult.getErrors ());} context.render (json (result)); }); }

Nu er den klasse, der understøtter forespørgselshandlingerne, dvs. UserQuery. Som nævnt styres alle metoder, der henter data fra serveren til klienten, af denne klasse:

@GraphQLName ("forespørgsel") offentlig klasse UserQuery {@GraphQLField offentlig statisk bruger retrieveUser (DataFetchingEnvironment env, @NotNull @GraphQLName ("id") Streng-id) {// returner bruger} @GraphQLField offentlig statisk liste listeBrugere (DataFetchingEnvironment env) { // returliste over brugere}}

På samme måde som UserQuery, nu skaber vi UserMutation, som styrer alle de operationer, der har til hensigt at ændre nogle givne data, der er gemt på serversiden:

@GraphQLName ("mutation") offentlig klasse UserMutation {@GraphQLField offentlig statisk bruger createUser (DataFetchingEnvironment env, @NotNull @GraphQLName ("navn") Strengnavn, @NotNull @GraphQLName ("e-mail") E-mail med streng) {// Opret bruger Information } }

Det er værd at bemærke kommentarerne i begge UserQuery og UserMutation klasser: @GraphQLName ("forespørgsel") og @GraphQLName (“mutation”). Disse kommentarer bruges til at definere henholdsvis forespørgsel og mutationsoperationer.

Med GraphQL-java-serveren, der er i stand til at køre forespørgslen og mutationsoperationen, kan vi bruge følgende JSON-nyttelast til at teste klientens anmodning mod serveren:

  • Til CREATE-operationen:
{"forespørgsel": "mutation ($ name: String! $ email: String!) {createUser (name: $ name email: $ email) {id name email age}}", "parameters": {"name": " John "," email ":" [email protected] "}} 

Som svar fra serveren til denne handling:

{"data": {"createUser": {"id": 1, "name": "John", "email": "[email protected]"}}
  • Til RETRIEVE-operationen:
{"forespørgsel": "forespørgsel ($ id: String!) {retrieveUser (id: $ id) {name email}}", "parameters": {"id": 1}}

Som svar fra serveren til denne handling:

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

GraphQL indeholder funktioner, som klienten kan tilpasse svaret. Så i den sidste RETRIEVE-operation, der blev brugt som eksemplet, i stedet for at returnere navn og e-mail, kan vi f.eks. Kun returnere e-mailen:

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

Så de returnerende oplysninger fra GraphQL-serveren returnerer kun de ønskede data:

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

5. Konklusion

GraphQL er en nem og ret attraktiv måde at minimere kompleksiteten mellem klient / server som en alternativ tilgang til REST API'er.

Som altid er eksemplet tilgængeligt i vores GitHub-lager.


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