Inleiding tot GraphQL

1. Overzicht

GraphQL is een querytaal, gemaakt door Facebook met als doel clienttoepassingen te bouwen op basis van intuïtieve en flexibele syntaxis, voor het beschrijven van hun gegevensvereisten en interacties.

Een van de belangrijkste uitdagingen bij traditionele REST-oproepen is het onvermogen van de klant om een ​​aangepaste (beperkte of uitgebreide) set gegevens aan te vragen. In de meeste gevallen krijgt de client, zodra hij informatie van de server opvraagt, alle of geen van de velden.

Een andere moeilijkheid is het werken en onderhouden van meerdere eindpunten. Naarmate een platform groeit, zal het aantal dus toenemen. Daarom moeten klanten vaak om gegevens van verschillende eindpunten vragen.

Bij het bouwen van een GraphQL-server is het slechts nodig om één URL te hebben voor het ophalen en muteren van gegevens. Een client kan dus een set gegevens opvragen door een queryreeks naar een server te sturen, die beschrijft wat ze willen.

2. Fundamentele GraphQL-nomenclatuur

Laten we eens kijken naar de basisterminologie van GraphQL.

  • Vraag: is een alleen-lezen bewerking die wordt aangevraagd bij een GraphQL-server
  • Mutatie: is een lees-schrijfbewerking die wordt aangevraagd bij een GraphQL-server
  • Oplosser: In GraphQL is het Resolver is verantwoordelijk voor het in kaart brengen van de operatie en de code die op de backend draait en die verantwoordelijk is voor het afhandelen van het verzoek. Het is analoog aan MVC-backend in een RESTFul-applicatie
  • Type: EEN Type definieert de vorm van responsgegevens die kunnen worden geretourneerd vanaf de GraphQL-server, inclusief velden die randen naar andere zijn Types
  • Invoer: zoals een Type, maar definieert de vorm van invoergegevens die naar een GraphQL-server worden gestuurd
  • Scalair: is een primitief Type, zoals een Draad, Int, Boolean, Vlotter, enz
  • Koppel: Een interface slaat de namen van de velden en hun argumenten op, zodat GraphQL-objecten ervan kunnen erven, waardoor het gebruik van specifieke velden wordt gegarandeerd
  • Schema: In GraphQL beheert het Schema queries en mutaties en definieert het wat er mag worden uitgevoerd op de GraphQL-server

2.1. Schema wordt geladen

Er zijn twee manieren om een ​​schema in de GraphQL-server te laden:

  1. door GraphQL's Interface Definition Language (IDL) te gebruiken
  2. door een van de ondersteunde programmeertalen te gebruiken

Laten we een voorbeeld demonstreren met IDL:

typ Gebruiker {firstName: String}

Nu een voorbeeld van schemadefinitie met Java-code:

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

3. Interfacedefinitietaal

Interface Definition Language (IDL) of Schema Definition Language (SDL) is de meest beknopte manier om een ​​GraphQL-schema te specificeren. De syntaxis is goed gedefinieerd en zal worden overgenomen in de officiële GraphQL-specificatie.

Laten we bijvoorbeeld een GraphQL-schema voor een gebruiker maken / e-mails kunnen als volgt worden gespecificeerd:

schema {query: QueryType} enum Geslacht {MALE FEMALE} type Gebruiker {id: String! firstName: String! lastName: String! createdAt: DateTime! leeftijd: Int! @default (waarde: 0) geslacht: [Geslacht]! e-mails: [E-mail!]! @relation (name: "Emails")} typ E-mail {id: String! e-mail: String! standaard: Int! @default (waarde: 0) gebruiker: Gebruiker @relation (naam: "E-mails")}

4. GraphQL-java

GraphQL-java is een implementatie gebaseerd op de specificatie en de JavaScript-referentie-implementatie. Merk op dat het minimaal Java 8 vereist om correct te werken.

4.1. GraphQL-java-annotaties

GraphQL maakt het ook mogelijk om Java-annotaties te gebruiken om de schemadefinitie te genereren zonder alle standaardcode die is gemaakt door het gebruik van de traditionele IDL-benadering.

4.2. Afhankelijkheden

Om ons voorbeeld te maken, laten we eerst beginnen met het importeren van de vereiste afhankelijkheid die vertrouwt op de Graphql-java-annotatiemodule:

 com.graphql-java graphql-java-annotaties 3.0.3 

We implementeren ook een HTTP-bibliotheek om de installatie in onze applicatie te vergemakkelijken. We gaan Ratpack gebruiken (hoewel het ook kan worden geïmplementeerd met Vert.x, Spark, Dropwizard, Spring Boot, etc.).

Laten we ook de Ratpack-afhankelijkheid importeren:

 io.ratpack ratpack-core 1.4.6 

4.3. Implementatie

Laten we ons voorbeeld maken: een eenvoudige API die gebruikers een "CRUDL" (aanmaken, ophalen, bijwerken, verwijderen en lijst) biedt. Laten we eerst onze Gebruiker POJO:

@GraphQLName ("gebruiker") openbare klasse Gebruiker {@GraphQLField privé Lange id; @GraphQLField private String naam; @GraphQLField private String e-mail; // getters, setters, constructors en helper-methoden weggelaten}

In deze POJO kunnen we de @GraphQLName ("gebruiker") annotatie, als een indicatie dat deze klasse in kaart is gebracht door GraphQL samen met elk veld dat is geannoteerd met @GraphQLField.

Vervolgens maken we het UserHandler klasse. Deze klasse erft van de gekozen HTTP-connectorbibliotheek (in ons geval Ratpack) een handlermethode, die de GraphQL's beheert en aanroept Resolver voorzien zijn van. Dus het verzoek (JSON-payloads) omleiden naar de juiste query of mutatiebewerking:

@Override public void handle (Context context) gooit Uitzondering {context.parse (Map.class). Dan (payload -> {Map parameters = (Map) payload.get ("parameters"); ExecutionResult executionResult = graphql .execute (payload .get (SchemaUtils.QUERY) .toString (), null, dit, parameters); Map result = new LinkedHashMap (); if (executionResult.getErrors (). isEmpty ()) {result.put (SchemaUtils.DATA, executionResult. getData ());} else {result.put (SchemaUtils.ERRORS, executionResult.getErrors ()); LOGGER.warning ("Fouten:" + executionResult.getErrors ());} context.render (json (resultaat)); }); }

Nu, de klasse die de querybewerkingen ondersteunt, d.w.z. UserQuery. Zoals vermeld worden alle methoden die gegevens van de server naar de client ophalen, beheerd door deze klasse:

@GraphQLName ("query") openbare klasse UserQuery {@GraphQLField openbare statische gebruiker retrieveUser (DataFetchingEnvironment env, @NotNull @GraphQLName ("id") String-id) {// return gebruiker} @GraphQLField openbare statische lijst listUsers (DataFetchingEnvironment env) { // lijst met gebruikers retourneren}}

gelijk aan UserQuery, nu creëren we UserMutation, die alle bewerkingen zal beheren die van plan zijn om bepaalde gegevens die op de server zijn opgeslagen te wijzigen:

@GraphQLName ("mutation") public class UserMutation {@GraphQLField public static User createUser (DataFetchingEnvironment env, @NotNull @GraphQLName ("name") String name, @NotNull @GraphQLName ("email") String e-mail) {// gebruiker aanmaken informatie } }

Het is de moeite waard om de annotaties in beide op te merken UserQuery en UserMutation klassen: @GraphQLName ("vraag") en @GraphQLName ("mutatie"). Die annotaties worden gebruikt om respectievelijk de query- en mutatiebewerkingen te definiëren.

Omdat de GraphQL-java-server de query- en mutatiebewerkingen kan uitvoeren, kunnen we de volgende JSON-payloads gebruiken om het verzoek van de client ten opzichte van de server te testen:

  • Voor de CREATE-bewerking:
{"query": "mutation ($ name: String! $ email: String!) {createUser (name: $ name email: $ email) {id name email age}}", "parameters": {"name": " John "," email ":" [email protected] "}} 

Als antwoord van de server voor deze bewerking:

{"data": {"createUser": {"id": 1, "name": "John", "email": "[email protected]"}}}
  • Voor de OPHALEN bewerking:
{"query": "query ($ id: String!) {retrieveUser (id: $ id) {naam e-mail}}", "parameters": {"id": 1}}

Als antwoord van de server voor deze bewerking:

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

GraphQL biedt functies waarmee de klant het antwoord kan aanpassen. Dus in de laatste bewerking OPHALEN die als voorbeeld is gebruikt, kunnen we in plaats van de naam en het e-mailadres te retourneren, bijvoorbeeld alleen de e-mail retourneren:

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

De geretourneerde informatie van de GraphQL-server retourneert dus alleen de gevraagde gegevens:

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

5. Conclusie

GraphQL is een gemakkelijke en vrij aantrekkelijke manier om de complexiteit tussen client / server te minimaliseren als een alternatieve benadering voor REST API's.

Zoals altijd is het voorbeeld beschikbaar in onze GitHub-repository.