Dieser Artikel wurde von Ryan Chenkie geprüft. Vielen Dank an alle Peer -Rezensenten von SitePoint, die SitePoint -Inhalte so gut wie möglich gemacht haben!
Daten vom Server auf der Clientseite anfordern, ist kein neues Konzept. Es ermöglicht eine Anwendung, Daten zu laden, ohne die Seite aktualisieren zu müssen. Dies wird in einzelnen Seitenanwendungen am meisten verwendet, die anstatt eine gerenderte Seite vom Server zu erhalten, nur die Daten anfordern, die zum Rendern von Client -Seite erforderlich sind.
Der häufigste Ansatz im Internet in den letzten Jahren war der restliche Architekturstil. Dieser Ansatz bringt jedoch einige Einschränkungen für Anwendungen mit hoher Datenbedarf. In einem erholsamen System müssen wir mehrere HTTP -Anfragen stellen, um alle gewünschten Daten zu erfassen, was eine erhebliche Leistungswirkung hat. Was wäre, wenn es eine Möglichkeit gäbe, mehrere Ressourcen in einer einzelnen HTTP -Anfrage anzufordern?
Einführung von GraphQL, eine Abfragesprache, die die Kommunikation zwischen Client und Serverseite vereint. Es ermöglicht der Client -Seite, genau die Daten in einer einzigen Anfrage zu beschreiben.
In diesem Artikel erstellen wir einen Node.js/Express -Server mit einer GraphQL -Route, die alle unsere Abfragen und Mutationen behandelt. Wir werden diese Route dann testen, indem wir einige Postanfragen senden und das Ergebnis mit dem Postboten analysieren.
finden Sie hier den vollständigen Quellcode für diese Anwendung. Ich habe auch eine Postman -Sammlung erstellt, die Sie hier herunterladen können.
Erstellen Sie als erstes unseren Node.js -Server mit dem Express -Framework. Wir werden auch MongoDB zusammen mit Mongoose für Datenpersistenz und Babel verwenden, um ES6 zu verwenden. Da der Code zur Laufzeit auf ES5 transpiliert wird, ist kein Build -Prozess erforderlich. Dies geschieht im Index.js:
<span>// index.js </span><span>require('babel/register'); </span><span>require('./app'); </span>
In App.js starten wir unseren Server, verbinden sich mit einer Mongo -Datenbank und erstellen Sie eine GraphQL -Route.
<span>// app.js </span><span>import express from 'express'; </span><span>import graphqlHTTP from 'express-graphql'; </span><span>import mongoose from 'mongoose'; </span> <span>import schema from './graphql'; </span> <span>var app = express(); </span> <span>// GraphqQL server route </span>app<span>.use('/graphql', graphqlHTTP(req => ({ </span> schema<span>, </span> <span>pretty: true </span><span>}))); </span> <span>// Connect mongo database </span>mongoose<span>.connect('mongodb://localhost/graphql'); </span> <span>// start server </span><span>var server = app.listen(8080, () => { </span> <span>console.log('Listening at port', server.address().port); </span><span>}); </span>
In diesem Artikelkontext definieren wir unsere GraphQL -Route. Wir verwenden Express-Graphql, eine Express Middleware, die vom GraphQL-Team von Facebook entwickelt wurde. Dadurch wird die HTTP -Anforderung über GraphQL verarbeitet und die JSON -Antwort zurückgegeben. Damit dies funktioniert, müssen wir die Optionen unseres GraphQL -Schemas durchlaufen, das im nächsten Abschnitt erörtert wird. Wir stellen auch die Option hübsch auf true fest. Dies macht die JSON-Antworten ziemlich gedruckt und erleichtert das Lesen.
für GraphQL, um unsere Anfragen zu verstehen, müssen wir ein Schema definieren. Und ein GraphQL -Schema ist nichts anderes als eine Gruppe von Abfragen und Mutationen. Sie können Abfragen als Ressourcen vorstellen, um aus der Datenbank und Mutationen abzurufen, als jede Art von Aktualisierung Ihrer Datenbank. Wir werden als Beispiel einen Blogpost und ein Kommentarmongoose -Modell erstellen und dann einige Abfragen und Mutationen dafür erstellen.
Beginnen wir zunächst die Mongoose -Modelle. Ich werde hier nicht viel Details eingehen, da Mongoose nicht im Mittelpunkt dieses Artikels steht. Sie finden die beiden Modelle in Modellen/Blog-post.js und Modellen/comment.js.
Wie bei Mongoose müssen wir in GraphQL unsere Datenstruktur definieren. Der Unterschied besteht darin, dass wir für jede Abfrage und Mutation definieren, welche Art von Daten eingeben und was in der Antwort gesendet wird. Wenn diese Typen nicht übereinstimmen, wird ein Fehler geworfen. Obwohl es überflüssig erscheinen kann, haben wir bereits ein Schematmodell in Mongoose definiert, aber es hat großartige Vorteile, wie:
Sie können den Quellcode für die GraphQL -Typen in GraphQL/Typen/finden. Hier ist ein Beispiel für eins:
<span>// graphql/types/blog-post.js </span><span>import <span>{ </span></span><span> <span>GraphQLObjectType, </span></span><span> <span>GraphQLNonNull, </span></span><span> <span>GraphQLString, </span></span><span> <span>GraphQLID </span></span><span><span>}</span> from 'graphql'; </span> <span>export default new GraphQLObjectType({ </span> <span>name: 'BlogPost', </span> <span>fields: { </span> <span>_id: { </span> <span>type: new GraphQLNonNull(GraphQLID) </span> <span>}, </span> <span>title: { </span> <span>type: GraphQLString </span> <span>}, </span> <span>description: { </span> <span>type: GraphQLString </span> <span>} </span> <span>} </span><span>}); </span>
Hier definieren wir den AusgangsgraphQL -Typ des Blog -Beitrags, den wir beim Erstellen der Abfragen und Mutationen weiter verwenden werden. Beachten Sie, wie ähnlich die Struktur dem Mongoose Model Blogpost ist. Es kann die Duplizierung der Arbeit erscheinen, aber dies sind getrennte Bedenken. Das Mongoose -Modell definiert die Datenstruktur für die Datenbank. Der GraphQL -Typ definiert eine Regel, was in einer Abfrage oder Mutation an Ihrem Server akzeptiert wird.
Mit den Mongoose -Modellen und den erstellten GraphQL -Typen können wir jetzt unser GraphQL -Schema erstellen.
<span>// graphql/index.js </span><span>import <span>{ </span></span><span> <span>GraphQLObjectType, </span></span><span> <span>GraphQLSchema </span></span><span><span>}</span> from 'graphql'; </span> <span>import mutations from './mutations'; </span><span>import queries from './queries'; </span> <span>export default new GraphQLSchema({ </span> <span>query: new GraphQLObjectType({ </span> <span>name: 'Query', </span> <span>fields: queries </span> <span>}), </span> <span>mutation: new GraphQLObjectType({ </span> <span>name: 'Mutation', </span> <span>fields: mutations </span> <span>}) </span><span>}); </span>
Hier exportieren wir ein GraphQlSchema, in dem wir zwei Eigenschaften definieren: Abfrage und Mutation. Ein GraphQLobjectype ist einer der vielen GraphQL -Typen. Insbesondere mit diesem können Sie angeben:
Wir importieren Abfragen und Mutationen von einem anderen Ort, dies ist nur für strukturelle Zwecke. Der Quellcode ist so strukturiert, dass unser Projekt gut skaliert werden kann, wenn wir weitere Modelle, Abfragen, Mutationen usw. usw. hinzufügen möchten.
Die Abfragen und Mutationenvariablen, die wir zu Feldern übergehen, sind einfache JavaScript -Objekte. Die Schlüssel sind die Mutation oder Abfragennamen. Die Werte sind einfache JavaScript -Objekte mit einer Konfiguration, mit der GraphQL mit ihnen zu tun ist. Nehmen wir die folgende GraphQL -Abfrage als Beispiel:
<span>// index.js </span><span>require('babel/register'); </span><span>require('./app'); </span>
für Grahpql, um zu verstehen, was mit dieser Abfrage zu tun ist, müssen wir die Blogposts und Kommentare abfragen. Unsere Abfragen variabel wären also so etwas wie folgt:
<span>// app.js </span><span>import express from 'express'; </span><span>import graphqlHTTP from 'express-graphql'; </span><span>import mongoose from 'mongoose'; </span> <span>import schema from './graphql'; </span> <span>var app = express(); </span> <span>// GraphqQL server route </span>app<span>.use('/graphql', graphqlHTTP(req => ({ </span> schema<span>, </span> <span>pretty: true </span><span>}))); </span> <span>// Connect mongo database </span>mongoose<span>.connect('mongodb://localhost/graphql'); </span> <span>// start server </span><span>var server = app.listen(8080, () => { </span> <span>console.log('Listening at port', server.address().port); </span><span>}); </span>
Gleiches gilt für Mutationen. Um zu erklären, dass es eine direkte Beziehung zwischen den Schlüssel gibt, die wir in unseren Fragen oder Mutationen haben, und den Namen, die wir in die Abfragen geben. Lassen Sie uns nun sehen, wie jede dieser Abfragen und Mutationen definiert wird.
Ausgehend von den Abfragen nehmen wir uns von einem Beispiel mit den bisher erstellten Modellen ab. Ein gutes Beispiel kann darin bestehen, einen Blog -Beitrag und alle seine Kommentare zu erhalten.
In einer REST -Lösung müssen Sie dafür zwei HTTP -Anfragen stellen. Eine, um den Blog -Beitrag und den anderen zu erhalten, um die Kommentare zu erhalten, die ungefähr so aussehen würden:
<span>// graphql/types/blog-post.js </span><span>import <span>{ </span></span><span> <span>GraphQLObjectType, </span></span><span> <span>GraphQLNonNull, </span></span><span> <span>GraphQLString, </span></span><span> <span>GraphQLID </span></span><span><span>}</span> from 'graphql'; </span> <span>export default new GraphQLObjectType({ </span> <span>name: 'BlogPost', </span> <span>fields: { </span> <span>_id: { </span> <span>type: new GraphQLNonNull(GraphQLID) </span> <span>}, </span> <span>title: { </span> <span>type: GraphQLString </span> <span>}, </span> <span>description: { </span> <span>type: GraphQLString </span> <span>} </span> <span>} </span><span>}); </span>
In GraphQL können wir dies nur in einer HTTP -Anforderung mit der folgenden Abfrage machen:
<span>// graphql/index.js </span><span>import <span>{ </span></span><span> <span>GraphQLObjectType, </span></span><span> <span>GraphQLSchema </span></span><span><span>}</span> from 'graphql'; </span> <span>import mutations from './mutations'; </span><span>import queries from './queries'; </span> <span>export default new GraphQLSchema({ </span> <span>query: new GraphQLObjectType({ </span> <span>name: 'Query', </span> <span>fields: queries </span> <span>}), </span> <span>mutation: new GraphQLObjectType({ </span> <span>name: 'Mutation', </span> <span>fields: mutations </span> <span>}) </span><span>}); </span>
Wir können alle gewünschten Daten in einer einzigen Anfrage abholen, was allein die Leistung verbessert. Wir können auch nach den genauen Eigenschaften fragen, die wir verwenden werden. Im obigen Beispiel bringt die Antwort nur den Titel und die Beschreibung des Blog -Beitrags, und die Kommentare bringen nur den Text.
Nur die erforderlichen Felder aus jeder Ressource abrufen, kann einen massiven Einfluss auf die Ladezeit einer Webseite oder Anwendung haben. Sehen wir uns zum Beispiel die Kommentare an, die auch eine _ID und eine postidische Eigenschaften haben. Jedes von diesen ist klein, jeweils 12 Bytes, um genau zu sein (nicht mit dem Objektschlüssel zählen). Dies hat wenig Auswirkungen, wenn es sich um eine einzige oder ein paar Kommentare handelt. Wenn wir über 200 Kommentare sprechen, sind dies über 4800 Bytes, die wir nicht einmal verwenden werden. Und das kann einen signifikanten Unterschied in der Anwendungsladezeit bewirken. Dies ist besonders wichtig für Geräte mit begrenzten Ressourcen wie mobilen, die normalerweise eine langsamere Netzwerkverbindung haben.
Damit dies funktioniert, müssen wir GraphQL mitteilen, wie die Daten für jede bestimmte Abfrage abgerufen werden. Sehen wir uns ein Beispiel für eine Abfragedefinition an:
<span>// index.js </span><span>require('babel/register'); </span><span>require('./app'); </span>
Hier erstellen wir eine Abfrage, die einen einzelnen Blog -Beitrag basierend auf einem ID -Parameter abruft. Beachten Sie, dass wir einen zuvor erstellten Typ angeben, der die Ausgabe der Abfrage validiert. Wir stellen auch ein Args -Objekt mit den erforderlichen Argumenten für diese Abfrage fest. Und schließlich eine Auflösungsfunktion, in der wir die Datenbank abfragen und die Daten zurückgeben.
Um den Prozess des Abholens von Daten weiter zu optimieren und die Projektionsfunktion auf MongoDB zu nutzen, verarbeiten wir das AST, dass GraphQL uns eine mit Mongoose kompatible Projektion erzeugt. Also, wenn wir die folgende Abfrage machen:
<span>// app.js </span><span>import express from 'express'; </span><span>import graphqlHTTP from 'express-graphql'; </span><span>import mongoose from 'mongoose'; </span> <span>import schema from './graphql'; </span> <span>var app = express(); </span> <span>// GraphqQL server route </span>app<span>.use('/graphql', graphqlHTTP(req => ({ </span> schema<span>, </span> <span>pretty: true </span><span>}))); </span> <span>// Connect mongo database </span>mongoose<span>.connect('mongodb://localhost/graphql'); </span> <span>// start server </span><span>var server = app.listen(8080, () => { </span> <span>console.log('Listening at port', server.address().port); </span><span>}); </span>
Da wir nur Titel und Beschreibung aus der Datenbank holen müssen, generiert die GetProjection -Funktion eine mongoose -gültige Projektion:
<span>// graphql/types/blog-post.js </span><span>import <span>{ </span></span><span> <span>GraphQLObjectType, </span></span><span> <span>GraphQLNonNull, </span></span><span> <span>GraphQLString, </span></span><span> <span>GraphQLID </span></span><span><span>}</span> from 'graphql'; </span> <span>export default new GraphQLObjectType({ </span> <span>name: 'BlogPost', </span> <span>fields: { </span> <span>_id: { </span> <span>type: new GraphQLNonNull(GraphQLID) </span> <span>}, </span> <span>title: { </span> <span>type: GraphQLString </span> <span>}, </span> <span>description: { </span> <span>type: GraphQLString </span> <span>} </span> <span>} </span><span>}); </span>
Sie können andere Abfragen unter GraphQL/Abfragen/* im Quellcode sehen. Wir werden nicht jeden durchlaufen, da sie alle dem obigen Beispiel ähnlich sind.
Mutationen sind Operationen, die eine Art Änderung in der Datenbank ausführen. Wie Abfragen können wir verschiedene Mutationen in einer einzelnen HTTP -Anfrage gruppieren. Normalerweise ist eine Aktion isoliert, wie z. B. „einen Kommentar hinzufügen“ oder „einen Blog -Beitrag erstellen“. Obwohl mit der steigenden Komplexität der Anwendungen und der Datenerfassung, für Analysen, Benutzererfahrungstests oder komplexe Vorgänge eine Benutzeraktion auf einer Website oder Anwendung eine beträchtliche Anzahl von Mutationen in unterschiedliche Ressourcen Ihrer Datenbank auslösen kann. Nach unserem Beispiel kann ein neuer Kommentar zu unserem Blog -Beitrag einen neuen Kommentar und ein Update für den Blog -Post -Kommentar bedeuten. In einer REST -Lösung hätten Sie so etwas wie Folgendes:
<span>// graphql/index.js </span><span>import <span>{ </span></span><span> <span>GraphQLObjectType, </span></span><span> <span>GraphQLSchema </span></span><span><span>}</span> from 'graphql'; </span> <span>import mutations from './mutations'; </span><span>import queries from './queries'; </span> <span>export default new GraphQLSchema({ </span> <span>query: new GraphQLObjectType({ </span> <span>name: 'Query', </span> <span>fields: queries </span> <span>}), </span> <span>mutation: new GraphQLObjectType({ </span> <span>name: 'Mutation', </span> <span>fields: mutations </span> <span>}) </span><span>}); </span>
Mit GraphQL können Sie es in nur einer HTTP -Anfrage mit so etwas wie folgt tun:
query <span>{ </span> blogPosts <span>{ </span> _id<span>, </span> title <span>} </span> comments <span>{ </span> text <span>} </span><span>} </span>
Beachten Sie, dass die Syntax für die Abfragen und Mutationen genau gleich ist und nur die Abfrage in die Mutation ändert. Wir können Daten aus einer Mutation auf die gleiche Weise fragen wie aus einer Abfrage. Indem wir ein Fragment nicht angeben, wie wir es in der obigen Abfrage für den BlogpostComportinc haben, fragen wir nur einen echten oder falschen Rückgabewert, der oft ausreicht, um die Operation zu bestätigen. Oder wir können einige Daten bitten, wie wir es für die AddComment -Mutation haben, die nützlich sein können, um Daten nur auf dem Server abzurufen.
Definieren wir dann unsere Mutationen auf unserem Server. Mutationen werden genau als Abfrage erstellt:
<span>{ </span> <span>blogPosts: {...}, </span> <span>comments: {...} </span><span>} </span>
Diese Mutation fügt einen neuen Blog -Beitrag hinzu und gibt es zurück, wenn er erfolgreich ist. Beachten Sie, wie wir beim Typen angeben, was zurückgegeben werden soll. In den Argumenten, die die Argumente der Mutation erhalten haben. Und eine Resolve () -Funktion genau wie in einer Abfragedefinition.
Jetzt, da wir unseren Express -Server mit einer GraphQL -Route und einigen Abfragen und Mutationen erstellt haben, lassen Sie ihn durch Senden einiger Anfragen an diese.
.Es gibt viele Möglichkeiten, Get oder Post -Anfragen an einen Ort zu senden, wie:
Es gibt mehr Lösungen als die oben beschriebenen. Die ersten beiden sind die bekanntesten und gebrauchten. GraphiQL ist die Lösung des GraphQL -Teams, um den Prozess mit GraphQL zu vereinfachen, da Abfragen komplexer zu schreiben können.
Aus diesen drei empfehle ich Graphiql, obwohl ich vor allem nach dem Postanlauf bevorzuge und empfehle. Dieses Tool ist definitiv ein Fortschritt bei API -Tests. Es bietet eine intuitive Schnittstelle, an der Sie Sammlungen jeder Art von Anforderung erstellen und speichern können. Sie können sogar Tests für Ihre API erstellen und sie mit dem Klicken einer Schaltfläche ausführen. Es verfügt auch über eine kollaborative Funktion und ermöglicht es, Anfragen Sammlungen auszutauschen. Ich habe also eine erstellt, die Sie hier herunterladen können, die Sie dann zum Postboten importieren können. Wenn Sie den Postman nicht installiert haben, empfehle ich Ihnen auf jeden Fall, dies zu tun.
Beginnen wir mit dem Ausführen des Servers. Sie sollten den Knoten 4 oder höher installiert haben. Wenn Sie dies nicht tun, empfehle ich, NVM zu installieren. Wir können dann Folgendes in der Befehlszeile ausführen:
<span>// index.js </span><span>require('babel/register'); </span><span>require('./app'); </span>
Der Server ist jetzt bereit, Anfragen zu erhalten. Lassen Sie uns also einige auf Postman erstellen. Unsere GraphQL -Route ist auf/GraphQL festgelegt. Als erstes muss der Ort so festgelegt werden, dass wir unsere Anfrage richten möchten. Wir müssen dann angeben, ob es sich um eine GET oder eine Postanfrage handelt. Obwohl Sie eine dieser Verwendung verwenden können, bevorzuge ich Post, da dies die URL nicht beeinflusst, was sie sauberer macht. Wir müssen auch den Header konfigurieren, der mit der Anforderung einhergeht. In unserem Fall müssen wir nur Inhalte hinzufügen, die der Anwendung/JSON entspricht. So sieht alles im Postboten ein:
Wir können jetzt den Körper erstellen, in dem unsere GraphQL -Abfrage und Variablen in einem JSON -Format wie folgt benötigt werden:
Unter der Annahme, dass Sie die von mir bereitgestellte Sammlung importiert haben, sollten Sie bereits einige Abfragen und Mutationsanfragen haben, die Sie testen können. Da ich hartcodierte Mongo-IDs verwendet habe, führen Sie die Anfragen in Ordnung aus und sie sollten alle erfolgreich sein. Analysieren Sie das, was ich in den Körper eines jeden einsetzt, und Sie werden sehen, dass dies nur eine Anwendung dessen ist, was in diesem Artikel diskutiert wurde. Wenn Sie die erste Anfrage mehr als einmal ausführen, können Sie sehen, wie Fehler zurückgegeben werden:
:
In diesem Artikel haben wir das Potenzial von GraphQL und wie es sich von einem Architekturstil in Ruhe unterscheidet. Diese neue Abfragesprache wird einen großen Einfluss auf das Web haben. Insbesondere für komplexere Datenanwendungen, die jetzt genau die gewünschten Daten beschreiben und diese mit einer einzelnen HTTP -Anforderung anfordern.
Ich würde gerne von Ihnen hören: Was denkst du über GraphQL und was war deine Erfahrung damit?
Wie definiere ich ein GraphQL -Schema für meine MongoDB -Daten? Ihre Daten und die Vorgänge, die Sie darauf ausführen können. In einer Node.js -Anwendung können Sie ein GraphQL -Schema mithilfe der GraphQL -Bibliothek definieren. Dies beinhaltet das Definieren von Typen für Ihre Daten, Felder für jeden Typ und die Abfragen und Mutationen, die an diesen Typen durchgeführt werden können. Die Typen sollten mit der Struktur der Dokumente in Ihren MongoDB -Sammlungen übereinstimmen. von Apollo Server. Diese Funktion wird aufgerufen, wenn ein Fehler in einen Resolver geworfen wird. Es empfängt den Fehler als Argument und sollte ein Fehlerobjekt zurückgeben. Dieses Objekt kann eine Nachricht, einen Statuscode und alle anderen relevanten Informationen enthalten. Sie können auch Try/Catch -Blöcke in Ihren Resolver verwenden, um Fehler zu fangen und zu behandeln.
Es gibt verschiedene Möglichkeiten, einen GraphQL -Server für die Leistung zu optimieren. Eine Möglichkeit besteht darin, Batching und Zwischenspeichern mit einer Bibliothek wie Dataloader zu verwenden. Dies kann die Anzahl der Anforderungen an Ihre MongoDB -Datenbank verringern und die Antwortzeiten verbessern. Eine andere Möglichkeit besteht darin, persistierte Abfragen zu verwenden, die die Größe der an den Server gesendeten Anforderungen verringern können. Sie können auch Überwachungstools wie Apollo Studio verwenden, um Leistungsengpässe zu identifizieren und zu beheben.
Wie kann ich meinen GraphQL -Server testen? und End-to-End-Tests. Sie können eine Bibliothek wie Scherz zum Schreiben der Tests und eine Bibliothek wie Supertest verwenden, um HTTP -Anforderungen an Ihren Server zu stellen. Sie sollten Ihre Resolver, Ihr Schema und Ihre MongoDB -Abfragen und Mutationen testen.
Wie kann ich meinen GraphQL -Server überwachen? Diese Dienste bieten Einblicke in die Leistung Ihres Servers, einschließlich Antwortzeiten, Fehlerraten und Nutzungsstatistiken. Sie können Sie auch benachrichtigen, wenn es Probleme mit Ihrem Server gibt. Diese Bibliothek bietet einen GraphQLUpload -Skalar, den Sie in Ihrem Schema verwenden können, und eine prozessigische Funktion, die Sie in Ihrer Middleware verwenden können, um die hochgeladenen Dateien zu verarbeiten.
Das obige ist der detaillierte Inhalt vonErstellen eines GraphQL -Servers mit node.js und mongoDB. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!