Wie baut man eine GraphQL API mit Nest.js?

In diesem Artikel erfahren Sie, wie Sie eine GraphQL-API mit NestJS erstellen und dabei die Vorteile seiner sauberen Architektur und Typsicherheit nutzen können.

NestJS ist ein NodeJS-Framework, das Benutzern hilft, skalierbare Backend-Anwendungen für Unternehmen zu erstellen, indem es Typsicherheit und ein strenges Architekturmuster bietet.

GraphQL ist eine Abfragesprache für Anwendungsprogrammierschnittstellen (APIs), die aufgrund ihrer Schnelligkeit und Stabilität als Alternative zu REST weit verbreitet ist, da sie auf Abfragen mit genau den Daten antwortet, die sie anfordern. Dieses GraphQL-Merkmal löst das Problem des Overfetching und Underfetching, das bei REST auftritt.

Einrichten Ihrer Entwicklungsumgebung

Wenn Sie die Nest.js CLI nicht global auf Ihrem System installiert haben, führen Sie den folgenden Befehl aus, um sie zu installieren:

npm i -g @nestjs/cli

Die Nest.js CLI enthält mehrere Befehle, mit denen Sie Boilerplate-Code generieren können, um Ihren Entwicklungsprozess zu vereinfachen.

Als Nächstes erstellen Sie das Projekt und generieren die erforderlichen Startdateien, indem Sie den folgenden Befehl ausführen:

nest new graphql-api

Führen Sie dann den folgenden Befehl aus, um in Ihr Projektverzeichnis zu wechseln:

cd graphql-api

Installieren Sie anschließend die erforderlichen Abhängigkeiten, indem Sie den folgenden Befehl ausführen:

npm i @nestjs/graphql @nestjs/apollo graphql apollo-server-express

Zu den oben installierten Abhängigkeiten gehören:

  • nest/graphql
  • nestjs/apollo
  • graphql
  • apollo-server-express

Als nächstes installieren Sie das TypeORM-Paket und den sqlite-Datenbanktreiber, indem Sie den folgenden Befehl ausführen:

npm install @nestjs/typeorm typeorm sqlite3

Sie benötigen die oben installierten Pakete, um sich mit einer Datenbank zu verbinden, sie zu lesen und zu beschreiben.

GraphQL in Nest.js konfigurieren

Nest.js bietet zwei Möglichkeiten zur Erstellung einer GraphQL-API: Code-first- und Schema-first-Ansätze.

Der Code-First-Ansatz beinhaltet die Verwendung von TypeScript-Dekoratoren und -Klassen zur Generierung des entsprechenden GraphQL-Schemas.

Der Schema-First-Ansatz sieht die Verwendung von GraphQL Schema Definition Language (SDL)-Dateien vor, während Nest.js TypeScript-Definitionen mit Klassen oder Schnittstellen auf der Grundlage des GraphQL-Schemas generiert.

In diesem Tutorium wird die Verwendung des Code-First-Ansatzes vorgestellt, um das Umschalten zwischen verschiedenen Sprachen zu vermeiden.

Um den Code First-Ansatz zu verwenden, navigieren Sie zur Eingangsdatei Ihrer Anwendung, app.module.ts, und importieren Sie GraphQLModule von @nestjs/graphql. Zum Beispiel so:

import { GraphQLModule } from '@nestjs/graphql';

Rufen Sie dann in Ihrem imports-Array die forRoot-Methode des GraphQLModuls auf. Diese Methode nimmt ein Konfigurationsobjekt als Argument an. Die Konfigurationsoptionen werden über den zugrundeliegenden GraphQL-Treiber übergeben (in diesem Tutorial wird der Apollo-Treiber verwendet). Setzen Sie die Eigenschaft autoSchemaFile im Konfigurationsobjekt auf schema.gql. Etwa so:

//app.module.ts
GraphQLModule.forRoot({ autoSchemaFile: 'schema.gql' }),

Die Eigenschaft autoSchemaFile ist der Dateipfad, in dem Ihr automatisch generiertes Schema gespeichert wird.

Verbinden mit einer Datenbank

Um Ihre Anwendung mit einer Datenbank zu verbinden, navigieren Sie zu Ihrer app.module.ts-Datei und importieren Sie TypeOrmModule von @nestjs/typeorm.

Etwa so:

import { TypeOrmModule } from '@nestjs/typeorm';

Fügen Sie dann den folgenden Codeblock zu Ihrem Import-Array hinzu:

TypeOrmModule.forRoot({
      type: 'sqlite',
      database: ':memory:',
      entities: ['dist/**/*.entity{.ts,.js}'],
      synchronize: true,
    }),

Der obige Codeblock erstellt eine Datenbankverbindung zwischen Ihrer Anwendung und einer Sqlite-Datenbank und teilt die Verbindung mit allen Modulen in Ihrer Anwendung.

Ressourcen generieren

Als nächstes erstellen Sie ein Modul, um Ihren Code zu organisieren, indem Sie den folgenden Befehl ausführen:

nest g module blog

Der obige Befehl erzeugt ein Blogmodul für Ihre Anwendung.

Führen Sie anschließend den folgenden Befehl aus, um einen Dienst zu erstellen:

nest g service blog

Der obige Codeblock erzeugt und registriert einen Dienst in Ihrer Anwendung. Dieser Dienst wird die gesamte Geschäftslogik für Ihre Anwendung enthalten und verarbeiten.

Führen Sie dann den folgenden Befehl aus, um einen Resolver zu erstellen:

nest g resolver

Der obige Codeblock erzeugt und registriert einen Resolver in Ihrer Anwendung. Ein Resolver spezifiziert Anweisungen für die Umwandlung von GraphQL-Abfragen und -Mutationen in Daten und gibt die in einem Schema angegebene Form der Daten synchron oder asynchron zurück.

Erstellen einer Entität

Eine Entität ist eine Sammlung von Feldern, die angibt, wie Daten in einer Datenbank gespeichert werden.

Um eine Entität zu erstellen, erstellen Sie in Ihrem Modulordner (Blog) eine Entitätsdatei gemäß der Konvention .entity.ts, z. B. blog.entity.ts.

Importieren Sie in Ihrer Entitätsdatei die Column, Entity und PrimaryGeneratedColumn aus typeorm. Zum Beispiel so:

import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';

Der Column Dekorator fügt die Felder, die er annotiert, als Spalten in einer Datenbank hinzu. Der Entity Dekorator markiert die Klasse die er annotiert als eine Entität. Der PrimaryGeneratedColumn Dekorator markiert die Eigenschaft die er annotiert als eindeutigen Bezeichner für Ihre Tabelle und generiert diese automatisch.

Als nächstes erstellen und exportieren Sie die Klasse Blog. Kommentieren Sie dann die Klasse mit dem Entity-Dekorator, um sie als Entität zu kennzeichnen. Zum Beispiel so:

@Entity()
export class Blog {}

Da dieses Tutorial eine Blog-API enthält, fügen Sie Ihrer Klasse die Eigenschaften id, title, body, author und date hinzu. Beschriften Sie dann jede der Eigenschaften mit dem Column Dekorator, außer der id Eigenschaft. Beschriften Sie die id-Eigenschaft mit dem PrimaryGeneratedColumn-Dekorator.

Etwa so:

import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
export class Blog {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  title: string;

  @Column()
  body: string;

  @Column()
  author: string;

  @Column()
  date: string;
}

Anlegen eines Objekttyps

Ein Objekttyp ist eine GraphQL-Schemadefinition, die das Objekt darstellt, mit dem der Client interagieren muss. Wenn Sie zum Beispiel eine Blog-API erstellen, müssen Sie das Blog-Schema/die Entität mit einer TypeScript-Klasse definieren und jedes Feld mit den entsprechenden Dekoratoren annotieren.

Als nächstes importieren Sie in Ihrer Entitätsdatei den Typ Int und die Dekoratoren Field und ObjectType aus @nestjs/graphql. Zum Beispiel so:

import { Field, Int, ObjectType } from '@nestjs/graphql';

Der Field-Dekorator kennzeichnet eine bestimmte Klasseneigenschaft als GraphQL-Feld. Nur Eigenschaften, die mit diesem Dekorator annotiert sind, werden im Schema definiert. Er akzeptiert eine optionale Rückgabetypfunktion und ein Konfigurationsobjekt als Argumente.

Der Typ Int ist erforderlich, um mögliche Mehrdeutigkeiten zwischen den Typsystemen von TypeScript und GraphQL zu beseitigen. Er ist nur für Eigenschaften mit Zahlenwerten erforderlich, da diese entweder Integer oder Float sein können.

Der ObjectType-Dekorator markiert eine Klasse als GraphQL-Typ.

Als nächstes annotieren Sie Ihre Blog-Klasse mit dem ObjectType-Dekorator, um sie als GraphQL-Typ zu kennzeichnen. Zum Beispiel so:

@ObjectType()
export class Blog {}

Schließlich geben Sie die erforderlichen Eigenschaften Ihres Typs innerhalb der Klasse an und kommentieren jede von ihnen mit dem Field-Dekorator. Zum Beispiel:

//blog.entity.ts
import { Field, Int, ObjectType } from '@nestjs/graphql';
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
@ObjectType()
export class Blog {
  @PrimaryGeneratedColumn()
  @Field((type) => Int)
  id: number;

  @Column()
  @Field()
  title: string;

  @Column()
  @Field()
  body: string;

  @Column()
  @Field()
  author: string;

  @Column()
  @Field()
  date: string;
}

Ihr fertiger Objekttyp sollte wie der obige Codeblock aussehen.

Beachten Sie, dass die id mit einem Zahlentyp im obigen Codeblock explizit als Ganzzahl angegeben wurde, um Mehrdeutigkeiten zwischen den Typsystemen von TypeScript und GraphQL zu vermeiden.

Schließlich injizieren Sie Ihre Entität in Ihre Anwendung, um eine Zugriffsschicht zwischen Ihrer Anwendung und Ihrer Datenbank zu schaffen.

Navigieren Sie dazu zu Ihrer Datei blog.module.ts, importieren Sie TypeOrmModule von @nestjs/typeorm und importieren Sie Ihre Blog-Entität.

Fügen Sie dann den unten stehenden Codeblock in Ihren Moduldekorator ein:

imports: [TypeOrmModule.forFeature([Blog])],

Der obige Codeblock erstellt ein Repository, das als Zugriffsebene zwischen Ihrer Anwendung und der Datenbank fungiert.

Einen Dienst erstellen

Navigieren Sie zu Ihrer zuvor erstellten Servicedatei blog.service.ts und importieren Sie InjectRepository von @nestjs/typeorm und Ihren Objekttyp.

Etwa so:

import { InjectRepository } from '@nestjs/typeorm';
import { Blog } from './blog.entity';

Als Nächstes fügen Sie den folgenden Codeblock in Ihre BlogService-Klasse ein, um Ihr Repository einzubinden:

constructor(
    @InjectRepository(Blog)
    private blogRepository: Repository<Blog>,
  ) {}

Fügen Sie anschließend den folgenden Codeblock zu Ihrer Dienstklasse hinzu, um die Logik zum Abrufen aller Blogs in der Datenbank zu implementieren:

async getAll(): Promise<Blog[]> {
    return await this.blogRepository.find();
  }

Als Nächstes müssen Sie die Logik für das Hinzufügen eines neuen Blogs zu Ihrer Datenbank implementieren, aber zuerst müssen Sie einen Eingabetyp erstellen.

Erstellen eines Eingabetyps

Um einen Eingabetyp für Ihre Mutationen zu erstellen, die komplexe Objekte annehmen, erstellen Sie einen dtos-Ordner in Ihrem Blog-Ordner. Erstellen Sie dann in Ihrem dtos-Ordner eine neue Datei, create-blog.input.ts.

Importieren Sie in Ihrer Datei create-blog.input.ts die Dekoratoren Field und InputType. Zum Beispiel so:

import { Field, InputType } from '@nestjs/graphql';

Der InputType-Dekorator markiert eine Klasse als GraphQL-Eingabetyp.

Als Nächstes erstellen und exportieren Sie eine Klasse, BlogInput. Kommentieren Sie dann die Klasse mit dem InputType-Dekorator. Zum Beispiel so:

@InputType()
export class BlogInput {}

Fügen Sie schließlich alle erforderlichen Blogeigenschaften hinzu und kommentieren Sie sie mit dem Felddekorator.

Etwa so:

//create-blog.input.ts
import { Field, InputType } from '@nestjs/graphql';

@InputType()
export class BlogInput {
  @Field()
  id: number;

  @Field()
  title: string;

  @Field()
  body: string;

  @Field()
  author: string;

  @Field()
  date: string;
}

Ihr fertiger Eingabetyp sollte wie der obige Codeblock aussehen.

Als Nächstes importieren Sie Ihren Eingabetyp in Ihre Servicedatei und fügen den unten stehenden Codeblock in Ihre Serviceklasse ein, um die Logik für das Hinzufügen eines Blogs zur Datenbank zu implementieren:

async createBlog(blogInput: BlogInput): Promise<Blog> {
    const newBlog = this.blogRepository.create(blogInput);

    return this.blogRepository.save(newBlog);
  }

Der Eingabetyp wird auf die gleiche Weise wie ein normales Nest.js-Datenübertragungsobjekt angewendet, als Validierungsmechanismus für eingehende Daten. Wie bei dtos können Sie mit dem Paket class-validator eine zusätzliche Validierung der Daten durchführen.

Einen Resolver erstellen

Navigieren Sie zu Ihrer zuvor erstellten Resolver-Datei blog.resolver.ts und importieren Sie Ihre Entität, den Eingabetyp und den Dienst. Zum Beispiel so:

import { Blog } from './blog.entity';
import { BlogService } from './blog.service';
import { BlogInput } from './dto/create-blog.input';

Als Nächstes fügen Sie den folgenden Codeblock in Ihre Resolver-Klasse ein, um Ihren Dienst in Ihren Resolver einzubinden:

constructor(private blogService: BlogService) {}

Als nächstes importieren Sie die Dekoratoren Args, Mutation und Query aus @nestjs/graphql.

Etwa so:

import { Args, Mutation, Query } from '@nestjs/graphql';

Der Args-Dekorator extrahiert das arguments-Objekt von der zugrundeliegenden Plattform und füllt den dekorierten Parameter mit dem Wert aller Argumente oder einem einzelnen angegebenen Argument.

Der Mutationsdekorator spezifiziert eine Route als Mutation.

Der Query-Dekorator spezifiziert eine Route als Abfrage.

Als nächstes übergeben Sie die unten stehende Funktion an den Resolver-Dekorator, um den Objekttyp anzugeben:

(of) => Blog

Fügen Sie dann den folgenden Codeblock zu Ihrer Resolver-Klasse hinzu, um die getAll-Methode aufzulösen.

 @Query((type) => [Blog])
  async getAllBlogs() {
    return this.blogService.getAll();
  }

Fügen Sie schließlich den folgenden Codeblock zu Ihrer Resolver-Klasse hinzu, um die createBlog-Methode aufzulösen.

 @Mutation((returns) => Blog)
  createBlog(@Args('blogInput') blogInput: BlogInput): Promise<Blog> {
    return this.blogService.createBlog(blogInput);
  }

Hinweis: Achten Sie darauf, dass Sie für jeden Dekorator die Funktion des Rückgabetyps angeben.

Ihre fertige Resolver-Klasse sollte wie der folgende Codeblock aussehen:

@Resolver((of) => Blog)
export class BlogResolver {
  constructor(private blogService: BlogService) {}

  @Query((type) => [Blog])
  async getAllBlogs() {
    return this.blogService.getAll();
  }

  @Mutation((returns) => Blog)
  createBlog(@Args('blogInput') blogInput: BlogInput): Promise<Blog> {
    return this.blogService.createBlog(blogInput);
  }
}

Testen Ihrer API mit dem GraphQL Playground

Um Ihre Anwendung mit dem standardmäßig verfügbaren GraphQL-Spielplatz zu testen, führen Sie den folgenden Befehl aus und navigieren Sie zu http://localhost:3000/graphql.

npm start

Als Nächstes sollten Sie eine Spielwiese sehen, auf der Sie Ihre Abfragen und Mutationen testen können, wie in der folgenden Abbildung dargestellt.

GraphQL-Spielplatz

Um alle Blogs aus der Datenbank abzurufen, führen Sie die folgende Abfrage aus:

query getAll{
  getAllBlogs {
    id,
    title,
    body,
    author,
    date
  }
}

Ein Beispiel ist in der nachstehenden Abbildung dargestellt:

Um ein Blog zu Ihrer Datenbank hinzuzufügen, führen Sie die folgende Mutation aus:

mutation createBlog {
  createBlog (blogInput: {
    id: 1, 
    title: "GraphQL is great", 
    body: "GraphQL APIs are faster than REST APIs", 
    author: "David Ekete",
    date: "01-02-03"
  }) {
    id,
    title,
    body,
    author,
    date,
  }
}

Ein Beispiel ist in der nachstehenden Abbildung dargestellt:

GraphQL-Spielplatz

Back4app und GraphQL

Aufgrund der vielen Vorteile, die GraphQL gegenüber REST hat, wie z.B. die Kontrolle über den Datenabruf, bietet die Back4app-Plattform eine GraphQL-API, die in Ihre auf der Plattform laufenden Parse-Anwendungen integriert ist.

Mit dieser Integration können Sie den Zustand Ihres Servers im Backend überprüfen, Create-, Read-, Update-, Delete-Operationen (CRUD) auf Ihrer Datenbank durchführen und vieles mehr, indem Sie einfache GraphQL-Abfragen und Mutationen schreiben.

Um zum Beispiel den Zustand Ihres Backend-Servers mit der GraphQL-API zu überprüfen, führen Sie die folgende Abfrage aus:

query Health {
  health
}

Die obige Abfrage wird zurückgegeben:

{
  "data": {
    "health": true
  }
}

Um mit der GraphQL-Funktion zu beginnen, navigieren Sie zu Ihrem Parse-Dashboard und wählen und klicken Sie auf Ihre App. Wählen Sie in der Benutzeroberfläche Ihrer App Core aus und klicken Sie darauf. Wählen Sie dann API-Konsole aus und klicken Sie darauf und wählen Sie die GraphQL-Konsole.

Wenn Sie den obigen Anweisungen folgen, öffnet sich eine GraphQL-Konsole, in der Sie Ihre Abfragen und Mutationen ausführen können, ähnlich dem GraphQL-Spielplatz, den Sie bei der Entwicklung verwendet haben. Sie können mehr über die GraphQL-Funktion von Back4app in der Back4app-Dokumentation erfahren.

Schlussfolgerung

In diesem Artikel wurde beschrieben, wie Sie eine GraphQL-API in Nest.js erstellen und die API mit dem GraphQL-Spielplatz testen können. GraphQL-APIs haben mehrere Vorteile gegenüber REST-APIs.

Sie sind jedoch nicht für jede Anwendung ideal. Berücksichtigen Sie die Vor- und Nachteile von GraphQL und REST, bevor Sie sich entscheiden, welche für Ihre Anwendung geeignet ist.

Unabhängig von Ihrer Wahl, GraphQL oder REST, müssen Sie Ihre Anwendung bereitstellen. Back4app ist ein auf Open-Source-Technologien basierendes Low-Code-BaaS, das Ihren Backend-Erstellungsprozess vereinfacht, indem es sich wiederholende Aufgaben mithilfe wiederverwendbarer Vorlagen eliminiert und den Großteil Ihrer Backend-Infrastruktur verwaltet.

Zu den Funktionen von Back4app gehören eine Echtzeit-Datenbank, Cloud-Funktionen, native APIs und SDKs, ein vollständiges Benutzerverwaltungssystem und vieles mehr.

Diese Plattform bietet auch eine kostenlose Ebene, die es Ihnen ermöglicht, die Plattform zu erkunden, ohne eine Gebühr zu zahlen.

Viel Spaß beim Bauen!

FAQ

Was ist GraphQL?

GraphQL ist eine Open-Source-Datenabfrage- und -bearbeitungssprache für APIs, die 2012 von Facebook entwickelt wurde.

Was ist Nest.JS?

Nest.JS ist ein Open-Source-Node.js-Framework zum Erstellen effizienter, skalierbarer serverseitiger Anwendungen.

Wie erstelle ich eine GraphQL-API mit Nest.JS?

– GraphQL in Nest.js konfigurieren
– Mit einer Datenbank verbinden
– Ressourcen generieren
– Entität erstellen
– Objekttyp erstellen
– Dienst erstellen


Leave a reply

Your email address will not be published.