Wie wir GraphQL in der Entwicklung am Beispiel des Internetkatalogs verwendet haben

In diesem Artikel teilen wir unsere Erfahrungen mit der realen Verwendung von GraphQL zum Erstellen eines Online-Katalogs. Lassen Sie uns über die Vor- und Nachteile dieser Abfragesprache sprechen, die wir bei Verwendung des GraphQL + Apollo-Clients Next JS (SSR) + TypeScript-Stacks gefunden haben.



Haftungsausschluss: Wir beschreiben die „magische Essenz“ und die Entstehungsgeschichte des Instruments nicht im Detail (darüber wurde bereits viel gesagt). Wir hoffen, dass diejenigen, die bereits mit GraphQL vertraut sind, von unserer praktischen Erfahrung profitieren.







Wir haben kürzlich an der Erstellung eines Internetkatalogs für Beleuchtungsgeräte teilgenommen. Zum Erstellen von Werbeseiten können Site-Administratoren den Designer verwenden: Wählen Sie die erforderlichen Blöcke (z. B. Banner oder Listen) aus, füllen Sie sie mit Daten, definieren Sie die Anzeigereihenfolge und andere Einstellungen. Gleichzeitig wurden in der Anwendung Komponenten gerendert, die für jeden Blocktyp vorab festgelegt wurden.



In jeder Kategorie des Online-Katalogs wurden Karten verschiedener Produktgruppen angezeigt. Wenn Sie mit der Maus über die Karte fahren, wurde eine Liste der Eigenschaften für die angehängten Produkte angezeigt.



Wir mussten die Eigenschaften von Waren in einer Baumstruktur anzeigen und eine ausreichend hohe Geschwindigkeit für die Bearbeitung von Anfragen bereitstellen.



Wir haben die folgende Arbeitsreihenfolge für Anfragen gewählt:



  1. Fordern Sie alle Produktgruppen für eine bestimmte Kategorie an (normalerweise ca. 50 Gruppen).
  2. Fordern Sie eine Produktliste für jede Gruppe an.
  3. Fordern Sie eine Liste der Eigenschaften für jedes Produkt an.


Da wir eine auf GraphQL basierende Anwendung entwickelten, waren wir darauf vorbereitet, dass einige der Daten eine ziemlich komplexe verschachtelte Struktur haben würden. Obwohl das Verzweigen dieser Struktur für die Backend-Entwicklung logisch war, musste eine "zusätzliche" Logik auf die Vorderseite geschrieben werden, um die Daten zu verarbeiten und sie entsprechend dem Design an die Komponente auszugeben.



Aufgrund der Natur des GraphQL-Konstruktors haben wir beschlossen, Eigenschaften und eindeutige Werte nicht auf der Rückseite, sondern auf der Vorderseite zu sammeln und sie dann in einer bestimmten Reihenfolge zu rendern. Die Bearbeitung der Anfrage war jedoch zu langsam - bis zu 20 Sekunden, was uns natürlich nicht zusagte.



Aus diesem Grund haben wir begonnen, jede Anforderung in kleine Unterabfragen zu unterteilen und Daten in Teilen zu laden. Infolgedessen verbesserte sich die Geschwindigkeit der Anwendung merklich - Anfragen dauerten nicht länger als 2 Sekunden. Obwohl die Anzahl der Anforderungen zugenommen hat, die Belastung des Systems abgenommen hat, ist die Notwendigkeit, nicht verwendete Daten zu laden, verschwunden.



Lassen Sie uns als nächstes direkt über die Arbeit mit GraphQL sprechen.



Funktionen der Arbeit mit GraphQL



Die Produktanforderungen waren, dass wir die von Facebook entwickelte GraphQL- Abfragesprache verwenden . Aus diesem Grund haben wir uns nicht endlosen Auseinandersetzungen hingegeben, was besser ist, GraphQL oder REST - stattdessen haben wir uns entschlossen, die richtige Technologie unter Berücksichtigung aller ihrer Stärken auf die effizienteste Weise einzusetzen.



Wir haben berücksichtigt, dass GraphQL die Entwicklung und Wartung von APIs vereinfachen soll, vor allem durch einen einzigen Endpunkt.



GET	/news
GET	/posts
POST	/news
POST	/post


GraphQL hat einen einzelnen Endpunkt. Dies bedeutet, dass wir keine zwei separaten Anforderungen stellen müssen, um Daten von zwei verschiedenen Ressourcen abzurufen. GraphQL konsolidiert alle Anforderungen und Mutationen in einem Endpunkt und stellt sie als Referenz zur Verfügung. Außerdem wird die Versionierung vermieden, die REST-APIs innewohnt.



GraphQL bietet die Möglichkeit, die Leistung zu optimieren und mithilfe einer speziellen Abfragesyntax genau die Daten zu erhalten, die derzeit benötigt werden: Die erforderlichen Felder müssen in der Abfrage aufgelistet werden.



const FETCH_USER_DATA = gql`
 query FetchUserData {
   user {
     firstName
     lastName
     date
   }
 }
`;


GraphQL verwendet stark typisierte Entitäten und Typschemata, was wiederum in Verbindung mit TypeScript und der Typgenerierung auf der Vorderseite nützlich ist.



Viele dieser Funktionen können sicherlich auf REST-APIs implementiert werden, GraphQL bietet sie jedoch sofort an.



Für die Client-Interaktion mit GraphQL haben wir die beliebteste Lösung mit guter Dokumentation ausgewählt - die Apollo Client-Bibliothek, mit der Sie Anwendungsdaten abrufen, zwischenspeichern und ändern können. Mit Apollo Client können Sie Anforderungs- und Mutations-Hooks und -Tools verwenden, um den Download- / Fehlerstatus einfach zu verfolgen.



Auch auf der Vorderseite haben wir das NextJS-Framework verwendet, das unter Berücksichtigung der folgenden Faktoren ausgewählt wurde: Pre-Rendering (NextJS bietet einen sehr einfachen Mechanismus für die sofortige Implementierung der statischen Generierung und SSR), Unterstützung für alle vorhandenen CSS-in-JS-Lösungen, dynamisches Routing, Unterstützung für statische Dateien (z. B. Bilder) in React-Komponenten.



Wenn die Technologien ausgewählt sind, fahren wir mit der Entwicklung fort. Auf den ersten Blick sieht alles gut aus: moderne Bibliotheken, gute Dokumentation, viele verschiedene Anwendungsfälle. Jede der Technologien ist individuell konzipiert, um eine komfortable und schnelle Entwicklung zu ermöglichen. Durch die Erstellung eines unverzichtbaren Boilerplates und das Entwerfen von UI-Komponenten näherten wir uns schrittweise der Phase einer effektiven Interaktion zwischen unseren Bibliotheken. Hier begann der ganze Spaß.



Wenn wir uns die Mechanismen von NextJS genauer ansehen, sehen wir, dass zwei Arten von Pre-Renderer verwendet werden: statische Generierung und SSR. Beide Strategien werden mithilfe spezieller Funktionen zum



Vorladen von Daten implementiert: `getInitialProps` (SSR) - Beim ersten Laden wird es auf dem Server ausgeführt, fordert Daten an und übergibt sie dann als Requisiten an die Komponente.



function Component ({data}) {
 ...
}
 
Component.getInitialProps = async (ctx) => {
 const res = await fetch('https://...')
 const json = await res.json()
 return { data: json.data }
}


`getStaticProps` (Static Generation) - wird in der Erstellungsphase ausgeführt. NextJS rendert die Seite mit den von dieser Funktion zurückgegebenen Requisiten vor.



export async function getStaticProps(context) {
 return {
   props: {}, //       props
 }
}


`getServerSideProps` (Server Side Rendering) - NextJS rendert die Seite bei jeder Anforderung vorab und verwendet die von dieser Funktion zurückgegebenen Daten als Requisiten.



export async function getServerSideProps(context) {
 return {
   props: {}, //       props
 }
}


Somit werden alle aufgelisteten Funktionen außerhalb der Komponente deklariert, empfangen einige Daten und übergeben sie an die Komponente. Dies führt zu einem der Probleme bei der Interaktion mit dem Apollo Client. Die Bibliothek bietet Abfragemechanismen wie den Hook "useQuery" und die Komponente "Query", und keine der vorgeschlagenen Methoden kann außerhalb der Komponente verwendet werden. Vor diesem Hintergrund haben wir uns in unserem Projekt für die Next-with-Apollo-Bibliothek entschieden und waren am Ende mit dem Ergebnis zufrieden.



Ein weiteres bekanntes Problem mit Apollo Client, auf das wir ebenfalls gestoßen sind, ist die Möglichkeit einer Endlosschleife von Anforderungen aus dem Hook "useQuery". Der Kern des Problems besteht darin, dass der Apollo-Client weiterhin unbegrenzt Anforderungen sendet, bis er erfolgreich Daten empfängt. Dies kann dazu führen, dass die Komponente in einer unendlichen Anforderung "hängt", wenn der Server aus irgendeinem Grund keine Daten zurückgeben kann.



In unserem Fall war einer der Gründe die Änderung des Schemas auf der Rückseite. Apollo generiert die Typen selbst. Wenn wir also Abfragen auf der Vorderseite schreiben, mussten wir den generierten Typen folgen, um Fehler zu vermeiden. Zum Beispiel hatten wir eine Arbeitsanfrage ohne Typprobleme. Beim Ändern des Schemas auf der Rückwandplatine wurden jedoch gleichzeitig die Typen geändert, wodurch die Arbeitsanforderung möglicherweise nicht mehr funktioniert. Vor diesem Hintergrund ist es optimal, die Protokollierung und ein klares Fehlerbehandlungssystem sofort zu implementieren, um die Nerven und Zeit des Teams zu sparen.



Unserer Meinung nach hat es sich als sehr nützlich erwiesen, dass Sie in graphql-Abfragen genau angeben können, welche Daten empfangen werden sollen. Wenn Sie eine große Anzahl von Anforderungen senden, wird die Verarbeitung unnötiger Daten vermieden. Dies kann wiederum die Leistung erheblich beeinträchtigen, wenn die Datenmenge zunimmt.



Es ist erwähnenswert, dass einer der Vorteile von GraphQL in der Bequemlichkeit der Entwicklung und der API-Unterstützung liegt. Diese Eigenschaft ist jedoch für die Backend-Entwicklung von größerer Bedeutung und hat nach unseren Beobachtungen keinen wesentlichen Einfluss auf die Front. Aufgrund der Generierung von Typen haben wir jedes Mal, wenn das Schema auf der Rückwandplatine geändert wurde, alle betroffenen Abfragen neu geschrieben. Beck musste das Schema auch verfeinern, wenn wir etwas an die Front bringen wollten, das noch nicht implementiert worden war. Gleichzeitig ermöglichte die Generierung von Typen bei Verwendung von TypeScript, dass beim Schreiben des Codes viele Fehler abgefangen wurden.



Zusammenfassen



Nach unseren Beobachtungen wird GraphQL häufig in verschiedenen Arten von IT-Lösungen verwendet und bietet dem Entwicklungsteam bestimmte Vorteile. Lassen Sie uns die Hauptfunktionen von GraphQL zusammenfassen, auf die wir bei der Entwicklung des Projekts gestoßen sind:



  • . graphql , TypeScript .
  • . GraphQL - . , ( , ). graphql «» ,
  • . graphql- , . .
  • . GraphQL , .


! , .



All Articles