So erstellen Sie eine sichere Node.js-GraphQL-API

Veröffentlicht: 2022-03-11

In diesem Artikel möchten wir Ihnen eine Kurzanleitung zum Erstellen einer sicheren Node.js-GraphQL-API präsentieren.

Einige Fragen, die Ihnen in den Sinn kommen, könnten sein:

  • Was ist der Zweck der Verwendung einer GraphQL-API?
  • Was ist eine GraphQL-API?
  • Was ist eine GraphQL-Abfrage?
  • Was ist der Vorteil von GraphQL?
  • Ist GraphQL besser als REST?
  • Warum verwenden wir Node.js?

All das sind berechtigte Fragen, aber bevor wir sie beantworten, sollten wir einen kurzen Überblick über den aktuellen Stand der Webentwicklung geben:

  • Fast jede Lösung, die Sie heute finden, verwendet eine Art Anwendungsprogrammierschnittstelle (API).
  • Selbst wenn Sie nur ein soziales Netzwerk wie Facebook oder Instagram verwenden, sind Sie immer noch mit einem Front-End verbunden, das eine API verwendet.
  • Wenn Sie neugierig sind, werden Sie feststellen, dass fast alle Online-Unterhaltungsdienste eine andere Art von API verwenden, einschließlich Dienste wie Netflix, Spotify und YouTube.

In praktisch jedem Szenario finden Sie eine API, die Sie nicht im Detail kennen müssen, z. B. müssen Sie nicht wissen, wie sie erstellt wurden, und Sie müssen nicht dieselbe Technologie verwenden, die sie früher waren in Ihr eigenes System integrieren können. Die bereitgestellte API ermöglicht es Ihnen, eine Möglichkeit zur Kommunikation zwischen Diensten in einem gemeinsamen Standard anzubieten, mit dem sowohl der Dienst als auch der Client kommunizieren können, ohne von einem bestimmten Technologie-Stack abhängig zu sein.

Mit einer gut strukturierten API ist es möglich, eine solide, wartbare und skalierbare API zu haben, die mehrere Arten von Clients und Front-End-Anwendungen bedienen kann.

Was ist die GraphQL-API?

GraphQL ist eine Abfragesprache für APIs, die für den internen Gebrauch in Facebook entwickelt und 2015 für die öffentliche Nutzung veröffentlicht wurde. Sie unterstützt Lesen, Schreiben und Aktualisierungen in Echtzeit. Es ist auch Open Source und wird häufig mit REST und anderen Architekturen verglichen. Es basiert, kurz gesagt, auf:

  • GraphQL-Abfragen – Dies ermöglicht dem Client zu lesen und zu manipulieren, wie die Daten empfangen werden sollen.
  • GraphQL-Mutationen - So schreiben Sie Daten auf den Server. Es ist die GraphQL-Konvention zum Schreiben von Daten in das System.

Obwohl dieser Artikel ein einfaches, aber reales Szenario zum Erstellen und Verwenden von GraphQL-APIs demonstrieren soll, bieten wir keine detaillierte Einführung in GraphQL. Der Grund ist einfach, da das GraphQL-Team eine umfassende Dokumentation bereitstellt und mehrere Best Practices in seiner Einführung in GraphQL auflistet.

Was ist eine GraphQL-Abfrage?

Wie zuvor beschrieben, ist eine Abfrage die Art und Weise, wie ein Client Daten von der API lesen und bearbeiten kann. Sie können den Typ eines Objekts übergeben und auswählen, welche Art von Feldern Sie zurückerhalten möchten. Eine einfache Abfrage würde wie folgt aussehen:

 query{ users{ firstName, lastName } }

In dieser Abfrage versuchen wir, alle Benutzer aus dem Schema unserer Benutzer zu erreichen, erhalten aber nur firstName und lastName . Das Ergebnis dieser Abfrage sieht beispielsweise so aus:

 { "data": { "users": [ { "firstName": "Marcos", "lastName": "Silva" }, { "firstName": "Paulo", "lastName": "Silva" } ] } }

Es ist ziemlich einfach für die Client-Nutzung.

Was ist der Zweck der Verwendung einer GraphQL-API?

Der Zweck der Erstellung einer API ist die Möglichkeit, Software als Service zu haben, die von anderen externen Diensten integriert werden kann. Selbst wenn Ihre Anwendung von einem einzigen Front-End genutzt wird, können Sie dieses Front-End als externen Dienst betrachten und dafür in verschiedenen Projekten arbeiten, wenn die Kommunikation zwischen den beiden über die API bereitgestellt wird.

Wenn Sie in einem großen Team arbeiten, kann es aufgeteilt werden, um ein Front-End- und ein Back-End-Team zu bilden, sodass beide dieselbe Technologie verwenden und ihre Arbeit erleichtern können. Bei der Entwicklung einer API ist es wichtig, diejenige auszuwählen, die besser zum Projekt passt und was Sie Ihrer gewünschten Lösung näher bringt.

In diesem Artikel konzentrieren wir uns auf ein Skelett zum Erstellen einer API, die GraphQL verwendet.

Ist GraphQL besser als REST?

Es mag ein bisschen wie eine Ausrede sein, aber ich kann nichts dafür: Das hängt davon ab .

GraphQL ist ein Ansatz, der sehr gut zu mehreren Szenarien passt. REST ist ein Architekturansatz, der sich ebenfalls in mehreren Szenarien bewährt hat. Heutzutage gibt es unzählige Artikel, die erklären, warum das eine besser ist als das andere oder warum Sie nur REST anstelle von GraphQL verwenden sollten. Und auch viele Möglichkeiten, wie Sie GraphQL intern verwenden und dennoch die Endpunkte der API als REST-basierte Architektur verwalten können.

Die beste Anleitung wäre, die Vorteile jedes Ansatzes zu kennen, die von Ihnen erstellte Lösung zu analysieren, zu bewerten, wie gut Ihr Team mit der Lösung arbeitet, und einzuschätzen, ob Sie in der Lage sein werden, Ihr Team beim Lernen und Ankommen anzuleiten Beschleunigen Sie schnell, bevor Sie zwischen den Ansätzen wählen.

Dieser Artikel ist eher ein praktischer Leitfaden als ein subjektiver Vergleich von GraphQL und REST. Falls Sie einen detaillierten Vergleich der beiden lesen möchten, schlage ich vor, dass Sie sich einen anderen unserer Artikel ansehen, GraphQL vs. REST – Ein GraphQL-Tutorial.

Im heutigen Artikel konzentrieren wir uns auf die Erstellung einer GraphQL-API mit Node.js.

Warum verwenden wir Node.js?

GraphQL hat mehrere verschiedene Bibliotheken, die Sie verwenden können. Für die Zwecke dieses Artikels haben wir uns für die Idee entschieden, JavaScript mit Node.js zu verwenden, da sie weit verbreitet sind und Entwickler mit Node.js vertraute Front-End-Syntax für die serverseitige Entwicklung verwenden können.

Es ist auch nützlich, unseren Ansatz mit einer REST-basierten API zu vergleichen, ähnlich dem, der in einem anderen Toptal Engineering Blog-Artikel demonstriert wurde: Erstellen einer sicheren REST-API in Node.js. Dieser Artikel zeigt auch die Verwendung von Node.js mit Express zur Entwicklung einer Skelett-REST-API, mit der Sie einige Unterschiede zwischen diesen beiden Ansätzen vergleichen können. Node.js wurde auch mit skalierbaren Netzwerkanwendungen, einer globalen Community und mehreren Open-Source-Bibliotheken entwickelt, die Sie auf der npm-Website finden können.

Dieses Mal werden wir zeigen, wie man mit GraphQL, Node.js und Express eine Skelett-API erstellt!

Praktisches GraphQL-Tutorial

Wie bereits erwähnt, erstellen wir eine Grundidee für die GraphQL-API, und Sie müssen die Grundlagen von Node.js und Express kennen, bevor Sie fortfahren. Der Quellcode des für dieses GraphQL-Beispiel erstellten Projekts ist hier verfügbar.

Wir werden mit zwei Arten von Ressourcen umgehen:

  • Benutzer, für die wir eine grundlegende CRUD handhaben.
  • Produkte, für die wir ein paar Details haben werden, um mehr von der Leistungsfähigkeit von GraphQL zu zeigen.

Die Benutzer enthalten die folgende Struktur:

  • Ich würde
  • Vorname
  • Familienname, Nachname
  • Email
  • Passwort
  • Berechtigungsstufe

Die Produkte enthalten die folgende Struktur:

  • Ich würde
  • Name
  • Bezeichnung
  • Preis

Was den Codierungsstandard betrifft, werden wir für dieses Projekt TypeScript verwenden. In der Quelldatei können Sie alles konfigurieren, um mit dem Codieren mit TypeScript zu beginnen.

Lassen Sie uns codieren!

Stellen Sie zunächst sicher, dass Sie die neueste Version von Node.js installiert haben. Zum Zeitpunkt der Veröffentlichung ist die aktuelle Version 10.15.3, laut Nodejs.org.

Initialisieren des Projekts

Beginnen wir in einem neuen Ordner, den wir node-graphql . Dort können wir ein Terminal oder eine Git-CLI-Konsole öffnen und die Magie mit dem folgenden Befehl starten: npm init .

Konfigurieren unserer Abhängigkeiten und TypeScript

Um den Vorgang zu beschleunigen, sollte das Ersetzen Ihrer package.json durch Folgendes in unserem Git-Repository alle erforderlichen Abhängigkeiten enthalten:

 { "name": "node-graphql", "version": "1.0.0", "description": "", "main": "dist/index.js", "scripts": { "tsc": "tsc", "start": "npm run tsc && node ./build/app.js" }, "author": "", "license": "ISC", "dependencies": { "@types/express": "^4.16.1", "@types/express-graphql": "^0.6.2", "@types/graphql": "^14.0.7", "express": "^4.16.4", "express-graphql": "^0.7.1", "graphql": "^14.1.1", "graphql-tools": "^4.0.4" }, "devDependencies": { "tslint": "^5.14.0", "typescript": "^3.3.4000" } }

Drücken Sie mit der aktualisierten package.json einfach erneut auf das Terminal und verwenden Sie: npm install . Es werden alle Abhängigkeiten installiert, die zum Ausführen dieser GraphQL-API in Node.js und Express erforderlich sind.

Als nächstes konfigurieren wir unseren TypeScript-Modus. Wir benötigen eine Datei namens tsconfig.json in unserem Stammordner mit folgendem Inhalt:

 { "compilerOptions": { "target": "ES2016", "module": "commonjs", "outDir": "./build", "strict": true, "esModuleInterop": true } }

Die Logik des Codes für diese Konfiguration ist im App-Ordner vorhanden. Dort können wir eine app.ts -Datei erstellen und dort für grundlegende Tests den folgenden Code hinzufügen:

 console.log('Hello Graphql Node API tutorial');

Durch unsere Konfiguration können wir jetzt npm start ausführen und auf einen Build warten und testen, ob alles ordnungsgemäß funktioniert. In Ihrer Terminalkonsole sollten Sie unser „Hello GraphQL Node API Tutorial“ sehen. In der Hintergrundszene kompiliert die Konfiguration im Wesentlichen den TypeScript-Code in reines JavaScript und führt dann unseren Build im build -Ordner aus.

Lassen Sie uns nun ein Grundgerüst für unsere GraphQL-API konfigurieren. Um unser Projekt zu starten, werden wir drei grundlegende Importe hinzufügen:

  • ausdrücken
  • Express-graphql
  • Graphql-Tools

Fangen wir an, alles zusammenzufügen:

 import express from 'express'; import graphqlHTTP from 'express-graphql'; import {makeExecutableSchema} from 'graphql-tools';

Jetzt sollten wir in der Lage sein, ein bisschen zu programmieren. Der nächste Schritt ist der Umgang mit unserer App in Express und der grundlegenden GraphQL-Konfiguration wie:

 import express from 'express'; import graphqlHTTP from 'express-graphql'; import {makeExecutableSchema} from 'graphql-tools'; const app: express.Application = express(); const port = 3000; let typeDefs: any = [` type Query { hello: String } type Mutation { hello(message: String) : String } `]; let helloMessage: String = 'World!'; let resolvers = { Query: { hello: () => helloMessage }, Mutation: { hello: (_: any, helloData: any) => { helloMessage = helloData.message; return helloMessage; } } }; app.use( '/graphql', graphqlHTTP({ schema: makeExecutableSchema({typeDefs, resolvers}), graphiql: true }) ); app.listen(port, () => console.log(`Node Graphql API listening on port ${port}!`));

Was wir tun ist:

  • Aktivieren von Port 3000 für unsere Express-Server-App.
  • Definieren, welche Abfragen und Mutationen wir als schnelles Beispiel verwenden möchten.
  • Definieren, wie die Abfragen und Mutationen funktionieren werden.

OK, aber was passiert mit typeDefs und Resolvern sowie der Beziehung zu Abfragen und Mutationen?

  • typeDefs – Die Definition unseres Schemas dessen, was wir von Abfragen und Mutationen erwarten können.
  • Resolver - Anstelle der Erwartung von Feldern oder erforderlichen Parametern definieren wir hier die Funktionen und Verhaltensweisen, wie die Abfragen und Mutationen funktionieren sollen.
  • Abfragen - Die „Gets“, die wir vom Server lesen möchten.
  • Mutationen - Unsere Anfragen, die sich auf alle Daten auswirken, die wir auf unserem eigenen Server haben.

Lassen Sie uns jetzt npm start erneut ausführen, um zu sehen, was wir dort haben. Wir würden erwarten, dass die App mit der folgenden Meldung ausgeführt wird: Node Graphql API listening on port 3000!

Wir können jetzt versuchen, die GraphQL-API auf unserem eigenen Server abzufragen und zu testen über: http://localhost:3000/graphql

GraphQL-Tutorial: Servertest

Toll, jetzt können wir unsere erste eigene Abfrage schreiben, die als „Hallo“ definiert wurde.

GraphQL-Tutorial: erste Abfrage

Beachten Sie, dass die Seite uns so, wie wir sie bei den typeDefs definiert haben, beim Erstellen der Abfrage helfen kann.

Das ist großartig, aber wie können wir den Wert ändern? Mutationen!

Sehen wir uns nun an, was passiert, wenn wir unseren In-Memory-Wert mit einer Mutation ändern:

GraphQL-Tutorial: Demonstration der Mutation

Jetzt können wir grundlegende CRUD-Operationen mit unserer GraphQL Node.js-API durchführen. Lassen Sie uns jetzt mit unserem Code fortfahren.

Produkte

Für Produkte verwenden wir ein Modul namens Produkte. Um diesen Artikel zu vereinfachen, verwenden wir nur zu Demonstrationszwecken eine In-Memory-Datenbank. Wir werden ein Modell und einen Service zur Verwaltung von Produkten definieren.

Unser Modell wird wie folgt basieren:

 export class Product { private id: Number = 0; private name: String = ''; private description: String = ''; private price: Number = 0; constructor(productId: Number, productName: String, productDescription: String, price: Number) { this.id = productId; this.name = productName; this.description = productDescription; this.price = price; } }

Der Dienst, der mit GraphQL kommuniziert, wird wie folgt definiert:

 export class ProductsService { public products: any = []; configTypeDefs() { let typeDefs = ` type Product { name: String, description: String, id: Int, price: Int } `; typeDefs += ` extend type Query { products: [Product] } `; typeDefs += ` extend type Mutation { product(name:String, id:Int, description: String, price: Int): Product! }`; return typeDefs; } configResolvers(resolvers: any) { resolvers.Query.products = () => { return this.products; }; resolvers.Mutation.product = (_: any, product: any) => { this.products.push(product); return product; }; } }

Benutzer

Für Benutzer folgen wir der gleichen Struktur wie das Produktmodul. Wir werden ein Modell und einen Service für Benutzer haben. Das Modell wird definiert als:

 export class User { private id: Number = 0; private firstName: String = ''; private lastName: String = ''; private email: String = ''; private password: String = ''; private permissionLevel: Number = 1; constructor(id: Number, firstName: String, lastName: String, email: String, password: String, permissionLevel: Number) { this.id = id; this.firstName = firstName; this.lastName = lastName; this.email = email; this.password = password; this.permissionLevel = permissionLevel; } }

In der Zwischenzeit wird unser Service wie folgt sein:

 const crypto = require('crypto'); export class UsersService { public users: any = []; configTypeDefs() { let typeDefs = ` type User { firstName: String, lastName: String, id: Int, password: String, permissionLevel: Int, email: String } `; typeDefs += ` extend type Query { users: [User] } `; typeDefs += ` extend type Mutation { user(firstName:String, lastName: String, password: String, permissionLevel: Int, email: String, id:Int): User! }`; return typeDefs; } configResolvers(resolvers: any) { resolvers.Query.users = () => { return this.users; }; resolvers.Mutation.user = (_: any, user: any) => { let salt = crypto.randomBytes(16).toString('base64'); let hash = crypto.createHmac('sha512', salt).update(user.password).digest("base64"); user.password = hash; this.users.push(user); return user; }; } }

Zur Erinnerung: Der Quellcode steht unter diesem Link zur Verfügung.

Jetzt können wir unseren Code spielen und testen. Lassen Sie uns npm start ausführen. Wir werden den Server auf Port 3000 laufen lassen. Wir können jetzt auf GraphQL zum Testen unter http://localhost:3000/graphql zugreifen.

Versuchen wir eine Mutation, um einen Artikel zu unserer Produktliste hinzuzufügen:

Node.js GraphQL-Mutationsdemonstration

Um zu testen, ob es funktioniert hat, verwenden wir jetzt eine Abfrage für Produkte, erhalten aber nur id , name und price :

 query{ products{ id, name, price } } The response will be: { "data": { "products": [ { "id": 100, "name": "My amazing product", "price": 400 } ] } }

Und das ist es; das Produkt funktioniert wie erwartet. Jetzt können wir spielen und die Felder umschalten, wenn wir wollen. Sie können versuchen, eine Beschreibung hinzuzufügen:

 query{ products{ id, name, description, price } }

Jetzt können wir die Beschreibungen unserer Produkte haben. Versuchen wir es jetzt mit Benutzern.

 mutation{ user(id:200, firstName:"Marcos", lastName:"Silva", password:"amaz1ingP4ss", permissionLevel:9, email:"[email protected]") { id } }

Und eine Abfrage wird wie folgt aussehen:

 query{ users{ id, firstName, lastName, password, email } }

Mit einer Antwort wie:

 { "data": { "users": [ { "id": 200, "firstName": "Marcos", "lastName": "Silva", "password": "kpj6Mq0tGChGbZ+BT9Nw6RMCLReZEPPyBCaUS3X23lZwCCp1Ogb94/oqJlya0xOBdgEbUwqRSuZRjZGhCzLdeQ==", "email": "[email protected]" } ] } }

Und jetzt ist unser GraphQL-Skelett fertig! Von hier aus gibt es unzählige Schritte zu einer nützlichen, voll funktionsfähigen API, aber der grundlegende Kern ist jetzt festgelegt.

Zusammenfassung und abschließende Gedanken

Um es kurz zu machen, ist der Artikel ziemlich umfangreich mit vielen grundlegenden Informationen zur Entwicklung einer GraphQL-Node.js-API.

Sehen wir uns an, was wir bisher behandelt haben:

  • Verwendung von Node.js mit Express und GraphQL zum Erstellen einer GraphQL-API;
  • Grundlegende Verwendung von GraphQL;
  • Grundlegende Verwendung von Abfragen und Mutationen;
  • Grundlegender Ansatz zum Erstellen von Modulen für Ihr Projekt;
  • Testen unserer GraphQL-API;

Um uns mehr auf die Entwicklungsseite der Dinge zu konzentrieren, haben wir einige wichtige Punkte vermieden, die kurz wie folgt zusammengefasst werden können:

  • Validierungen für neue Artikel;
  • Richtiger Umgang mit Fehlern mit einem generischen Fehlerdienst;
  • Validieren von Feldern, die ein Benutzer bei jeder Anfrage mit einem generischen Dienst verwenden kann;
  • Fügen Sie einen JWT-Interceptor hinzu, um die API zu sichern;
  • Behandeln Sie Passwort-Hash mit einem effektiveren Ansatz;
  • Unit- und Integrationstests hinzufügen;

Denken Sie daran, dass wir den vollständigen Quellcode unter diesem Git-Link haben. Fühlen Sie sich frei, es zu verwenden, zu forken, Probleme zu öffnen, Pull-Anforderungen zu stellen und damit zu spielen! Bitte beachten Sie, dass alle Standards und Vorschläge in diesem Artikel nicht in Stein gemeißelt sind.

Dies ist nur einer von vielen Ansätzen, die verwendet werden können, um mit dem Entwerfen Ihrer eigenen GraphQL-API zu beginnen. Achten Sie auch darauf, GraphQL genauer zu lesen und zu erkunden, um zu erfahren, was es zu bieten hat und wie es Ihre APIs noch besser machen kann.