MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Das ABC von NestJS:Ein Leitfaden für Anfänger mit MongoDB (Mongoose).

Was ist NestJS?

NestJS ist ein modernes NodeJS-Framework, das beliebte NodeJS-Frameworks wie Express und Fastify im Hintergrund nutzt. NestJS wurde weitgehend von Angular inspiriert und verwendet daher ein Modulsystem im Angular-Stil. NestJS ist in TypeScript geschrieben, unterstützt aber auch natives JavaScript.

Voraussetzungen

Um diesem Tutorial zu folgen, müssen Sie die folgenden Anforderungen erfüllen

  • Kompetenz in PostMan oder einem anderen API-Testtool.
  • Grundkenntnisse von NodeJS und Express-Apps.
  • Grundkenntnisse von TypeScript.
  • Kompetenz in MongoDB (Mongoose).

Folgendes sollte auf Ihrem System installiert sein

  • NodeJS v.14 und höher.
  • Visual Studio Code (empfohlen) oder jede andere IDE.
  • PostMan oder ein anderes API-Testtool.

Gemeinsame Terminologien, die in NestJS verwendet werden;

Hier sind einige der am häufigsten verwendeten Begriffe in NestJS, denen Sie in diesem Artikel häufig begegnen werden.

Schnittstellen

Eine Schnittstelle ist eine Typdefinition. Daher wird es als Type Checker/Enforcer in Funktionen, Klassen usw. verwendet.

interface humanInterface{
  name:string;
  gender:string;
  age:number;
}

const kevin: humanInterface={
  name:'Kevin Sunders',
  gender:'Male',
  age: 25,
}

Das humanInterface oben führt eine strenge Typprüfung für kevin durch Objekt. Typoskript würde einen Fehler ausgeben, wenn Sie ein weiteres Feld hinzufügen oder den Typ einer der Objekteigenschaften ändern.

Controller

Controller sind dafür verantwortlich, eingehende Anfragen zu empfangen und dem Client zu antworten. Ein Controller arbeitet mit seinem zugehörigen Dienst zusammen.

Dienste

Ein Dienst ist ein Anbieter, der Daten speichert und abruft und mit seinem entsprechenden Controller verwendet wird.

Dekorateure

Ein Decorator ist ein Ausdruck, der eine Funktion zurückgibt und ein target akzeptiert , name , und property descriptor als optionale Argumente. Dekorateure werden als @decorator-name geschrieben . Sie werden normalerweise an Klassendeklarationen, Methoden und Parameter angehängt.

@Get()
   getAll(): Model[] {
    return this.testService.getAll();
  }

Der @Get Der obige Dekorator markiert den Codeblock darunter als GET Anfrage. Dazu später mehr.

Modul

Ein Modul ist ein Teil eines Programms, das eine bestimmte Aufgabe erledigt. Ein Modul in NestJS wird durch Annotieren einer Klasse gekennzeichnet, die mit @Module() annotiert ist Dekorateur. Nest verwendet die von @Module() bereitgestellten Metadaten decorator, um die Anwendungsstruktur zu organisieren.

CLI installieren

Um zu beginnen, müssen Sie die NestJS CLI **** mit npm installieren . Sie können diesen Schritt überspringen, wenn Sie die NestJS-Befehlszeilenschnittstelle bereits auf Ihrem System installiert haben.

npm i -g @nestjs/cli

Dieser obige Codeblock installiert die Nest-CLI global auf Ihrem System.

Erstellen eines neuen Projekts

Um ein neues Projekt zu generieren, führen Sie nest new aus gefolgt von Ihrem gewünschten Projektnamen. Für diesen Artikel schreiben wir eine einfache Blog-API mit CRUD-Funktionalität, während wir uns an RESTful-Standards halten.

nest new Blog-Api

Dieser Befehl fordert Sie auf, einen Paketmanager auszuwählen, wählen Sie npm .

Dadurch wird die gesamte Projektstruktur mit einem Test-API-Endpunkt aufgebaut, dessen Port auf 3000 gesetzt ist standardmäßig. Sie können es unter http://localhost:3000 testen nach dem Ausführen von npm run start:dev Befehl, der den Server im Watch-Modus startet, ähnlich wie nodemon in Express-Apps.

Nach dem Testen des Endpunkts müssen Sie einige der Standarddateien löschen, da Sie sie nicht mehr benötigen. Um dies zu tun;

  • Öffnen Sie den src-Ordner und darin
  • Löschen Sie app.controller.spec.ts ,
  • Löschen Sie app.controller.ts ,
  • Löschen Sie app.service.ts ,
  • Öffnen Sie app.module.ts ,
  • Entfernen Sie den Verweis auf AppController in den controllers Array und die Importe,
  • Entfernen Sie den Verweis auf AppService in den providers Array und die Importe.

Möglicherweise müssen Sie auch die README.md ändern um Ihre Spezifikationen zu erfüllen.

Ihre app.module.ts Datei sollte so aussehen,

//app.module.ts

import { Module } from '@nestjs/common';

@Module({
  imports: [],
  controllers: [],
  providers: [],
})
export class AppModule {}

Umgebungsvariablen

Als bewährte Methode sollten einige vertrauliche Informationen in Ihrem Code nicht veröffentlicht werden. Zum Beispiel Ihr PORT und Ihren MongoDB URI .

Lassen Sie uns dies in Ihrem Code beheben.

Auf Ihrem Terminal ausführen

npm i dotenv

Erstellen Sie dann eine .env Datei in Ihrem Verzeichnis und fügen Sie sie zu Ihrer .gitignore hinzu Datei. Speichern Sie Ihren PORT -Variable müssen Sie auch Ihren MongoDB URI speichern später an gleicher Stelle. Ersetzen Sie nun den exponierten PORT in Ihrer main.ts Datei. Importieren Sie dazu die Datei dotenv Paket und rufen Sie .config() auf Methode drauf.

import * as dotenv from 'dotenv';
dotenv.config();

Dies sollte Ihre main.ts sein Datei, nachdem Sie die obigen Schritte ausgeführt haben.

//main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as dotenv from 'dotenv';
dotenv.config();

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(process.env.PORT);
}
bootstrap();

Generieren von Modulen

Um ein NestJS-Modul mit der NestJS-CLI zu generieren, führen Sie das folgende Code-Snippet aus.

nest generate module blogs

Dieser Befehl erstellt ein blogs Ordner, der eine blogs.module.ts enthält Datei und registriert BlogsModule in Ihrer app.module.ts Datei.

Generieren von Schnittstellen

Lassen Sie uns mithilfe der NestJS-CLI eine Schnittstelle generieren, um die Typprüfung für das Objekt durchzuführen, das Ihre Blog-Posts darstellen wird. Um dies zu erreichen, müssen Sie zuerst cd in die blogs Ordner, da empfohlen wird, sie in der Nähe der Domänenobjekte zu speichern, denen sie zugeordnet sind.

cd src/blogs

Führen Sie dann das unten stehende Code-Snippet aus, um die Schnittstelle zu generieren.

nest generate interface blogs

dies erstellt eine blogs.interface.ts Datei. Hier definieren wir unsere Schnittstelle. wir nennen die Schnittstelle BlogsInterface .

export interface BlogsInterface {
  title: string;
  body: string;
  category: string;
  dateCreated: Date;
}

Bevor Sie weitere Befehle auf Ihrem Terminal ausführen, denken Sie an cd aus der src Ordner und durch Ausführen zurück in Ihren Stammordner

cd ../..

Generieren von Diensten und Controllern

Sie müssen eine Dienstklasse generieren, um Daten zu speichern und abzurufen und die gesamte Logik zu verarbeiten, sowie eine Controller-Klasse, um alle eingehenden Anforderungen und ausgehenden Antworten zu verarbeiten.

Dienst

Um einen Dienst zu generieren, führen Sie den folgenden Befehl aus:

nest generate service blogs

Dieser Befehl erstellt zwei Dateien:blogs.service.spec.ts und die blogs.service.ts und registriert den Dienst bei den providers -Array in blogs.module.ts .

Verantwortlicher

Um einen Controller zu generieren, führen Sie den folgenden Befehl aus:

nest generate controller blogs

Dieser Befehl erstellt zwei Dateien, die blogs.controller.spec.ts und die blogs.controller.ts und registriert den Controller im controllers -Array in blogs.module.ts .

Damit ist Ihre Blogstruktur fast vollständig, Sie müssen nur noch den BlogsService erstellen zugänglich für andere Teile Ihres Programms. Sie können dies erreichen, indem Sie einen exports erstellen -Array in blogs.module.ts -Datei und Registrieren des BlogsService in diesem Array.

//blogs.module.ts

import { Module } from '@nestjs/common';
import { BlogsService } from './blogs.service';
import { BlogsController } from './blogs.controller';

@Module({
  providers: [BlogsService],
  controllers: [BlogsController],
  exports: [BlogsService],
})
export class BlogsModule {}

MongoDB(Mongoose).

Installieren Sie Mungo, indem Sie ausführen,

npm install --save @nestjs/mongoose mongoose

Importieren Sie nach der Installation {MongooseModule} von '@nestjs/mongoose’ in Ihre app.module.ts Datei. Dann holen Sie sich Ihren MongoDB URI und speichern Sie es in Ihrer .env Datei. Wiederholen Sie die Schritte zum Importieren von dotenv in der app.module.ts Datei. Dann in den imports Array rufen Sie .forRoot() auf -Methode, die Ihren MongoDB URI übernimmt als Argument für das MongooseModule . Ähnlich wie mongoose.connect() in regulären Express-Apps.

@Module({
  imports: [BlogsModule, MongooseModule.forRoot(process.env.MONGODB_URI)],

Erstellen eines Schemas.

Lassen Sie uns ein Schema erstellen, um die Form der Blogs in unserer Sammlung zu definieren. Dazu

  • Erstellen Sie einen Ordner in Ihren blogs nennen Sie ihn schemas ,
  • Innerhalb der schemas Ordner, erstellen Sie eine Datei und nennen Sie sie blogs.schema.ts .

Dann

Zunächst müssen Sie,

  • Importieren Sie die prop Dekorateur, das schema decorator und die SchemaFactory von @nestjs/mongoose ,
  • Erstellen Sie eine Klasse Blog und exportieren,
  • Verwandeln Sie die Klasse in ein Schema, indem Sie @Schema() platzieren Dekorateur über der Klasse,
  • Erstellen Sie ein konstantes BlogSchema , weisen Sie den Rückgabewert des Aufrufs von .createForClass(Blog) zu mit dem Namen Ihrer Klasse als Argument für SchemaFactory die Sie zuvor importiert haben.
//blogs.schema.ts

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';

@Schema()
export class Blog {}

export const BlogSchema = SchemaFactory.createForClass(Blog);

Dann müssen Sie die Eigenschaften des Schemas definieren.

Um eine Eigenschaft im Schema zu definieren, müssen Sie jede von ihnen mit @prop() markieren Dekorateur. Der @prop decorator akzeptiert ein Optionsobjekt oder eine komplexe Typdeklaration. Die komplexen Typdeklarationen könnten Arrays und verschachtelte Objekttypdeklarationen sein.

//blogs.schema.ts

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';

@Schema()
export class Blog {
  @Prop({ required: true })
  title: string;

  @Prop({ required: true })
  body: string;

  @Prop({ required: true })
  category: string;

  @Prop({ required: true })
  dateCreated: Date;
}

export const BlogSchema = SchemaFactory.createForClass(Blog);

Als nächstes importieren Sie { Document } von 'mongoose' .

Erstellen Sie dann einen Union-Typ mit der Schema-Klasse und dem importierten Document . So,

//blogs.schema.ts

import { Document } from 'mongoose';

export type BlogDocument = Blog & Document;

Ihre endgültige blogs.schema.ts Datei sollte so aussehen,

import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

export type BlogDocument = Blog & Document;

@Schema()
export class Blog {
  @Prop({ required: true })
  title: string;

  @Prop({ required: true })
  body: string;

  @Prop({ required: true })
  category: string;

  @Prop({ required: true })
  dateCreated: Date;
}

export const BlogSchema = SchemaFactory.createForClass(Blog);

Schema registrieren

Sie müssen alles in Ihre blogs.module.ts importieren Datei. Um dies zu erreichen, müssen Sie,

  • Importiere {MongooseModule} von '@nestjs/mongoose’ ,
  • Importiere {Blog, BlogSchema} aus './schemas/blogs.schema’
  • Erstellen Sie einen imports Array innerhalb des @module Dekorateur
  • Rufen Sie .forFeature() auf -Methode auf dem MongooseModule . Dies nimmt ein Array auf, das ein Objekt enthält, das einen name definiert und ein schema -Eigenschaft, die auf Ihren Blog.name gesetzt werden sollte und Ihr BlogSchema bzw..
@Module({
  imports: [
    MongooseModule.forFeature([{ name: Blog.name, schema: BlogSchema }]),
  ],

Injizierendes Schema

Sie müssen den Blog einfügen model in blogs.service.ts mit @InjectModel() Dekorateur. Um dies zu erreichen, müssen Sie

  • importiere { Model } von 'mongoose' ,
  • importiere { InjectModel } von '@nestjs/mongoose’ ,
  • Importiere {Blog, BlogDocument} aus './schemas/blogs.schema’ ,
  • Erstellen Sie einen constructor innerhalb des BlogsService Klasse,
  • Deklarieren Sie einen private -Variable und nennen Sie sie blogModel und weisen Sie den Typ Model<BlogDocument> zu dazu. Alle Mungo-Methoden werden für diese Variable aufgerufen.

Denken Sie daran, BlogDocument ist der Vereinigungstyp des Blog -Klasse und das Mongoose Model die Sie zuvor erstellt haben. Er wird als generischer Typ für Ihre Variable verwendet.

  • Dekoriere blogModel mit @InjectModel() und übergeben Sie Blog.name als Argument.
constructor(
    @InjectModel(Blog.name)
    private blogModel: Model<BlogDocument>,
  ) {}

Funktionsweise des Routings

Inzwischen müssen Sie bemerkt haben, dass der @Controller decorator hat die Zeichenkette 'blogs' hineingegangen. Das bedeutet, dass der Controller alle Antworten sendet und alle Anfragen verarbeitet, die auf http://localhost/3000/blogs gestellt werden .

Als Nächstes implementieren Sie die Dienst- und Controller-Logik.

Dienst- und Controller-Logik.

Es ist endlich an der Zeit, Ihre CRUD-Funktionalität zu implementieren.

Bevor wir beginnen, müssen Sie Ihren Controller einrichten. Beginnen Sie damit, etwas HTTP zu importieren Methoden-Decorators in Ihren Controller.

//blogs.controller.ts

import {
  Controller,
  Body,
  Delete,
  Get,
  Post,
  Put,
  Param,
} from '@nestjs/common';

Anschließend müssen Sie den Dienst importieren und registrieren, damit Sie darauf zugreifen und die Schnittstelle zur Typprüfung importieren können.

//blogs.controller.ts

import { BlogsInterface } from './blogs.interface';
import { BlogsService } from './blogs.service';

Um Ihren Dienst zu registrieren, erstellen Sie einen constructor innerhalb des BlogsController Klasse und deklarieren Sie eine private readonly Variable service und setzen Sie seinen Typ auf BlogsService .

constructor(private readonly service: BlogsService) {}

Jetzt, da Sie alles eingerichtet haben, können wir loslegen.

Erstellen

Dienstlogik

Importieren Sie { BlogsInterface } aus './blogs.interface' und füge ein async hinzu Funktion an den BlogsService Klasse namens createBlog , die einen Parameter blog annehmen wird , mit seinem Typ als BlogInterface , und sein Rückgabetyp als Promise mit einem generischen <Blog> Typ.

async createBlog(blog: BlogsInterface): Promise<Blog> {
    return await new this.blogModel({
      ...blog,
      dateCreated: new Date(),
    }).save();
  }

Controller-Logik

In Ihrem BlogsController Klasse einen async hinzufügen Funktion für die Klasse. Nennen Sie es createBlog und markieren Sie es mit dem @Post decorator, der es als POST definiert Anfrage.createBlog nimmt einen Parameter blog , mit seinem Typ als BlogInterface . Markieren Sie den Parameter mit @Body decorator, der den gesamten body extrahiert Objekt aus req -Objekt und füllt den dekorierten Parameter mit dem Wert von body .

@Post()
  async createBlog(
    @Body()
    blog: BlogsInterface,
  ) {
    return await this.service.createBlog(blog);
  }

Lesen

Fügen Sie zwei async hinzu Methoden, eine zum Zurückgeben eines einzelnen Blogposts und die zweite zum Zurückgeben aller Blogposts.

Dienstlogik

async getAllBlogs(): Promise<Blog[]> {
    return await this.blogModel.find().exec();
  }

  async getBlog(id: string): Promise<Blog> {
    return await this.blogModel.findById(id);
  }

Controller-Logik

  @Get()
  async getAllBlogs() {
    return await this.service.getAllBlogs();
  }

  @Get(':id')
  async getBlog(@Param('id') id: string) {
    return await this.service.getBlog(id);
  }

Die async Funktionen sind mit dem @Get gekennzeichnet decorator, der es als GET definiert Anfrage.

Die zweite async Der Decorator der Funktion hat ein Argument ':id' . Das übergeben Sie an @Param Dekorateur. Der Parameter ist mit dem @Param('id') gekennzeichnet die die params extrahiert -Eigenschaft aus req -Objekt und füllt den dekorierten Parameter mit dem Wert von params .

Aktualisieren

Lassen Sie uns die Logik für PUT implementieren Anfrage.

Dienstlogik

async updateBlog(id: string, body: BlogsInterface): Promise<Blog> {
    return await this.blogModel.findByIdAndUpdate(id, body);
  }

Controller-Logik

@Put(':id')
  async updateBlog(
    @Param('id')
    id: string,
    @Body()
    blog: BlogsInterface,
  ) {
    return await this.service.updateBlog(id, blog);
  } 

Die async Der zweite Parameter der Funktion ist mit @Body() gekennzeichnet decorator, der den gesamten body extrahiert Objekt aus req -Objekt und füllt den dekorierten Parameter mit dem Wert von body .

Löschen

Lassen Sie uns die Logik für delete implementieren Anfragen.

Dienstlogik

async deleteBlog(id: string): Promise<void> {
    return await this.blogModel.findByIdAndDelete(id);
  }

Das Promise Der generische Typ ist void weil ein Delete Anfrage gibt ein leeres Promise zurück.

Controller-Logik

@Delete(':id')
  async deleteBlog(@Param('id') id: string) {
    return await this.service.deleteBlog(id);
  }

API testen

Um diese API zu testen, sollten Sie ein API-Testtool verwenden. Für diesen Artikel verwende ich ein beliebtes API-Testtool namens Postman. Ich werde zum Testen zufällige Daten zu beliebten Themen verwenden.

Erstellen

Erstellen Sie einen POST Anfrage an http://localhost/3000/blogs Mit den folgenden JSON-Objekten werden alle Daten zu Ihrer Datenbank hinzugefügt.

{
  "title": "jeen-yuhs",
  "body": "The life of superstar rapper Kanye West is currently streaming on Netflix - and according to our jeen-yuhs review, it's a fascinating watch. -credit:Radio Times",
  "category":"Music"
}

{
  "title": "Why You Should Always Wash Your Hands",
  "body": "Germs from unwashed hands can be transferred to other objects, like handrails, tabletops, or toys, and then transferred to another person's hands.-credit cdc.gov",
  "category":"Health"
}

{
  "title": "Why You Should Follow me on Twitter",
  "body": "Well, Because I asked nicely",
  "category":"Random"
}

Sie sollten einen 201 erhalten Antwort und das erstellte Blog mit einem Datum und einer _id hinzugefügt.

Lesen

Machen Sie ein GET Anfrage an http://localhost/3000/blogs . Dies sollte ein

zurückgeben

200 Antwort mit einem Array aller Daten, die Sie zuvor hinzugefügt haben. Kopieren Sie die _id -Eigenschaft eines der Array-Objekte.

Machen Sie ein weiteres GET Anfrage an http://localhost/3000/blogs/id mit der zuvor kopierten ID. Dies sollte einen 200 zurückgeben Antwort mit den Daten des Objekts, dessen ID verwendet wurde, um die Anfrage zu stellen.

Aktualisieren

Machen Sie einen PUT Anfrage an http://localhost/3000/blogs/id mit den unten stehenden Daten. Die id sollte durch die zuvor kopierte ersetzt werden. Dies sollte einen 200 zurückgeben Antwort und aktualisiert das Objekt mit der id hinter den Kulissen. wenn Sie ein weiteres GET ausführen Anforderung sollten Sie das aktualisierte Objekt erhalten.

{
  "title": "why you Should Cut your Nails",
  "body": "It's important to trim your nails regularly. Nail trimming together with manicures makes your nails look well-groomed, neat, and tidy.- credit:WebMD",
  "category":"Health"
}

Löschen

Machen Sie ein DELETE Anfrage an http://localhost/3000/blogs/id .Dies sollte einen 200 zurückgeben Antwort und löscht das Objekt mit der id hinter den Kulissen. wenn Sie ein weiteres GET ausführen Bitte sehen Sie das gelöschte Objekt nicht.

Fazit

Damit sind wir endlich am Ende dieses Artikels angelangt. Lassen Sie uns zusammenfassen, was Sie behandelt haben.

  • Was NestJS ist
  • Terminologien in NestJS,
  • Erstellen einer NestJS-App
  • Integration von MongoDB in eine NestJS-App
  • Manipulation und NestJS-App,

Das ist ziemlich viel, herzlichen Glückwunsch, dass Sie es so weit geschafft haben.

Den Code finden Sie auf github.

Viel Glück auf Ihrer NestJS-Reise!