Inhaltsübersicht

Vorteile der Verwendung von GraphQL gegenüber REST-APIs

Eines der häufigsten Probleme bei REST ist das Über- und Unterabrufen von Daten. Dies ist darauf zurückzuführen, dass die einzige Möglichkeit für einen Client, Daten herunterzuladen, darin besteht, auf Endpunkte zuzugreifen, die feste Datenstrukturen zurückgeben. Es ist schwierig, die API so zu gestalten, dass sie den Kunden genau die Daten liefert, die sie benötigen.

  • GraphQL reduziert Netzwerkanfragen, indem es uns ermöglicht, alle benötigten Daten in einer einzigen Abfrage zu holen oder abzurufen.
  • Mit GraphQL ist keine Versionierung erforderlich, da wir unserer GraphQL-API problemlos neue Felder und Typen hinzufügen können, ohne dass dies Auswirkungen auf bestehende Abfragen hat. Außerdem können wir Felder einfach als veraltet markieren, und die Felder werden aus der vom Server erhaltenen Antwort ausgeschlossen.
  • Mit GraphQL können Sie auch eine Low-Level-Leistungsüberwachung der von Ihrem Server verarbeiteten Anfragen durchführen. GraphQL verwendet das Konzept der Resolver-Funktionen, um die Daten zu sammeln, die ein Client anfordert. Die Instrumentierung und Messung der Leistung dieser Resolver liefert wichtige Erkenntnisse über Engpässe in Ihrem System.

Kurze Erläuterung der Funktionsweise von GraphQL

Die GraphQL-Implementierung besteht hauptsächlich aus drei Teilen

  • Schema - Beschreibt die Daten.
  • Resolver - Logik zum Abrufen von Daten aus verschiedenen Ressourcen (Microservices).
  • Abfrage - Der Kunde fragt, welche Daten abgerufen werden sollen.

Schema(Mehr über Schema und Typen)

➡️
type Query{getUsers:[User]getUser(user_id:Int!):User}type Mutation{addUser(first_name:String!,last_name:String,pic:String):Boolean deleteUser(user_id:Int!):Boolean}type User{first_name:Stringlast_name:Stringpic:Stringfull_name:Stringuser_id:Int!designation:String}

Der obige Code beschreibt, was abgefragt werden kann und welche Antwortdaten (Datentyp) von den Ressourcen erwartet werden.

P.S.: "!" bedeutet, dass das Feld nicht null oder undefiniert sein darf.

Resolver (der folgende Code ist in NodeJs geschrieben)

➡️
{Query:{getUsers:(obj,args,context,info) => { return users},getUser:(obj,{user_id},context,info) => { return users.find(user => user.user_id == user_id) } },Mutation:{ addUser:(obj,{first_name,last_name,pic},context,info) => { users.push({ first_name:first_name, last_name:last_name, pic:pic }) return true },deleteUser:(obj,{user_id},context,info) => { for (var i = 0; i < users.length; i++) { if(users[i].user_id == user_id){ users.splice(i,1) return true }}return false } }, User:{ full_name:(prev_obj,args,context,info) => { return `${prev_obj.first_name} ${prev_obj.last_name}`}}}

Der obige Code beschreibt die Logik, die ausgeführt wird, wenn der Client Anfragen stellt.

P.S. Ich habe die Funktion full_name resolver für den Typ User verwendet, um meine eigene Logik zu schreiben.

Abfrage(Mehr über Abfrage)

➡️
{getUsers{full_name pic}}

DerClient fragt mit dem obigen Code ab, der nur full_name und pic zurückgibt (siehe unten).

P.S. Der Client kann nur nach Feldern abfragen, die im Schema definiert sind.

➡️
{"data":{"getUsers":{"full_name":"Srinivasa Sainath", "pic":"https://vpms.xoxoday.com/images/xoxoday.png"}}}

Die Client-Anfrage kann aus Query und Mutation (und Subscription) bestehen. Dies wird in zukünftigen Blogs der GraphQL-Serie besprochen).

Beide Anfragen tun dasselbe. Nur dass die Mutation synchron ausgeführt wird. Die Konvention, die befolgt wird, ist, dass Mutation für jede Operation verwendet wird, die Schreibvorgänge auf dem Server verursacht (Profil aktualisieren, Bestellung erstellen usw.), und dass eine Abfrage für das Abrufen von Daten verwendet wird (Menü abrufen, Gutscheinliste abrufen usw.). ( Ähnlich wie GET und POST ). Technisch gesehen können beide Arten von Anfragen zur Ausführung jeder beliebigen Logik verwendet werden. Es ist jedoch besser, sich an die Konvention zu halten, da dies Ihrem Team hilft.

Wichtige Punkte zum Verständnis der Beziehung zwischen Auflösungsfunktionen und Abfrage

  • Sie können sich jedes Feld in einer GraphQL-Abfrage als eine Funktion oder Methode des vorherigen Typs vorstellen, die den nächsten Typ zurückgibt. Genau so funktioniert GraphQL. Jedes Feld jedes Typs wird von einer Funktion namens Resolver unterstützt, die vom Entwickler des GraphQL-Servers bereitgestellt wird. Der entsprechende Resolver wird aufgerufen, um den nächsten Wert zu erzeugen, wenn ein Feld ausgeführt wird.
  • Die Ausführung ist abgeschlossen, wenn ein Feld einen skalaren Wert wie eine Zeichenkette oder eine Zahl liefert. Wenn ein Feld jedoch einen Objektwert hat, enthält die Abfrage eine weitere Auswahl von Feldern, die sich auf dieses Objekt beziehen. Dies wird fortgesetzt, bis skalare Werte erreicht sind. GraphQL-Abfragen enden immer bei skalaren Werten.

Eine Auflösungsfunktion erhält vier Argumente

Syntax :

➡️
{getUsers:(obj,args,context,info) =>{ return users }}
  • obj Das vorherige Objekt, das für ein Feld auf dem Wurzelabfragetyp oft nicht verwendet wird.
    Zum Verständnis, mehr über dieses Argument siehe GraphQL Server mit Node.js.
  • args Die Argumente, die dem Feld in der GraphQL-Abfrage übergeben werden. In der obigen Resolver-Funktion ist {user_input} die args
  • context Ein Wert, der jedem Resolver zur Verfügung gestellt wird und wichtige Kontextinformationen wie den aktuell angemeldeten Benutzer oder den Zugang zu einer Datenbank enthält. Im obigen Resolver wird die Funktion context zur Übergabe von token_info verwendet
  • info Ein Wert, der feldspezifische Informationen enthält, die für die aktuelle Abfrage relevant sind, sowie die Schemadetails. Oft nicht verwendet
➡️
Clone the demo GraphQL project from here.P.S. In the next part of the GraphQL series, I will discuss how to implement GraphQL as an API Gateway.
Srinivasa Sainath

Srinivasa Sainath