MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

L'ABC di NestJS:una guida per principianti con MongoDB (Mongoose).

Che cos'è NestJS?

NestJS è un moderno framework NodeJS che utilizza sotto il cofano i più diffusi framework NodeJS come Express e Fastify. NestJS è stato ampiamente ispirato da Angular e, di conseguenza, utilizza un sistema di moduli in stile Angular. NestJS è scritto in TypeScript, sebbene supporti anche JavaScript nativo.

Prerequisiti

Per seguire questo tutorial, devi soddisfare i seguenti requisiti

  • Competenza in PostMan o in qualsiasi altro strumento di test API.
  • Conoscenza di base delle app NodeJS ed Express.
  • Conoscenza di base di TypeScript.
  • Competenza in MongoDB(Mangusta).

Quanto segue dovrebbe essere installato sul tuo sistema

  • NodeJS v.14 e versioni successive.
  • Codice Visual Studio (consigliato) o qualsiasi altro IDE.
  • PostMan o qualsiasi altro strumento di test API.

Terminologie comuni utilizzate in NestJS;

Ecco alcuni dei termini utilizzati più regolarmente in NestJS che incontrerai spesso in questo articolo.

Interfacce

Un'interfaccia è una definizione di tipo. Di conseguenza, viene utilizzato come controllo/enforcer del tipo in funzioni, classi, ecc.

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

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

L'humanInterface sopra esegue un controllo rigoroso del tipo su kevin oggetto. Typescript genererebbe un errore se aggiungessi un altro campo o cambiassi il tipo di una qualsiasi delle proprietà dell'oggetto.

Titolari del trattamento

I responsabili del trattamento sono incaricati di ricevere le richieste in arrivo e di rispondere al cliente. Un titolare del trattamento collabora con il servizio associato.

Servizi

Un servizio è un fornitore che archivia e recupera dati e viene utilizzato con il relativo titolare del trattamento.

Decoratori

Un decoratore è un'espressione che restituisce una funzione che accetta un target , name e property descriptor come argomenti facoltativi. I decoratori sono scritti come @decorator-name . Di solito sono allegati a dichiarazioni di classe, metodi e parametri.

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

Il @Get decorator sopra contrassegna il blocco di codice sotto di esso come GET richiesta. Ne parleremo più avanti.

Modulo

Un modulo è una parte di un programma che gestisce un compito particolare. Un modulo in NestJS è contrassegnato annotando una classe annotata con @Module() decoratore. Nest utilizza i metadati forniti da @Module() decoratore per organizzare la struttura dell'applicazione.

Installazione della CLI

Per iniziare dovrai installare NestJS CLI ****con npm . Puoi saltare questo passaggio se hai già installato l'interfaccia a riga di comando NestJS sul tuo sistema.

npm i -g @nestjs/cli

Questo blocco di codice sopra installerà la CLI nest a livello globale sul tuo sistema.

Creazione di un nuovo progetto

Per generare un nuovo progetto, esegui nest new seguito dal nome del progetto desiderato. Per questo articolo, scriveremo una semplice API per blog con funzionalità CRUD aderendo agli standard RESTful.

nest new Blog-Api

Questo comando ti chiederà di selezionare un gestore di pacchetti, scegli npm .

Questo quindi impalcherà l'intera struttura del progetto con un endpoint API di test la cui porta è impostata su 3000 per impostazione predefinita. Puoi testarlo su http://localhost:3000 dopo aver eseguito npm run start:dev comando che avvierà il server in modalità di controllo simile a quello che fa nodemon nelle app express.

Dopo aver testato l'endpoint, dovrai eliminare alcuni dei file predefiniti perché non ne avrai più bisogno. Per fare questo;

  • apri la cartella src e dentro,
  • elimina app.controller.spec.ts ,
  • elimina app.controller.ts ,
  • elimina app.service.ts ,
  • Apri app.module.ts ,
  • Rimuovi il riferimento a AppController nei controllers array e le importazioni,
  • Rimuovi il riferimento a AppService nei providers array e le importazioni.

Potrebbe anche essere necessario modificare il README.md per soddisfare le vostre specifiche.

Il tuo app.module.ts il file dovrebbe assomigliare a questo,

//app.module.ts

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

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

Variabili ambientali

Come buona pratica, alcune informazioni riservate nel codice non dovrebbero essere rese pubbliche. Ad esempio il tuo PORT e il tuo MongoDB URI .

Risolviamo questo problema nel tuo codice.

Sul tuo terminale corri

npm i dotenv

Quindi crea un .env file nella tua directory e aggiungilo al tuo .gitignore file. Memorizza il tuo PORT variabile, dovrai anche memorizzare il tuo MongoDB URI più tardi nello stesso luogo. Ora sostituisci il PORT esposto nel tuo main.ts file. Per fare ciò, importa il dotenv pacchetto e chiama il .config() metodo su di esso.

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

Questo dovrebbe essere il tuo main.ts file dopo aver seguito i passaggi precedenti.

//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();

Generazione di moduli

Per generare un modulo NestJS utilizzando l'interfaccia a riga di comando NestJS, esegui il frammento di codice riportato di seguito.

nest generate module blogs

Questo comando crea un blogs cartella che contiene un blogs.module.ts file e registra BlogsModule nel tuo app.module.ts file.

Generazione di interfacce

Generiamo un'interfaccia utilizzando NestJS CLI per eseguire il controllo del tipo per l'oggetto che rappresenterà i post del tuo blog. Per raggiungere questo obiettivo devi prima cd nei blogs cartella perché si consiglia di archiviarli vicino agli oggetti di dominio a cui sono associati.

cd src/blogs

Quindi esegui il frammento di codice di seguito per generare l'interfaccia.

nest generate interface blogs

questo crea un blogs.interface.ts file. Qui è dove definiremo la nostra interfaccia. chiameremo l'interfaccia BlogsInterface .

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

prima di eseguire altri comandi sul tuo terminale, ricorda di cd fuori dal src cartella e di nuovo nella cartella principale eseguendo

cd ../..

Generazione di servizi e controller

Dovrai generare una classe di servizio per archiviare e recuperare i dati e gestire tutta la logica e una classe controller per gestire tutte le richieste in entrata e le risposte in uscita.

Servizio

Per generare un servizio, esegui il comando seguente,

nest generate service blogs

Questo comando crea due file blogs.service.spec.ts e il blogs.service.ts e registra il servizio nei providers array nel blogs.module.ts .

Titolare

Per generare un controller, eseguire il comando seguente,

nest generate controller blogs

Questo comando crea due file blogs.controller.spec.ts e il blogs.controller.ts e registra il controller nei controllers array nel blogs.module.ts .

Con questi la struttura del tuo blog è quasi completa, devi solo creare il BlogsService accessibile ad altre parti del programma. Puoi ottenerlo creando un exports array nel blogs.module.ts file e registrando il BlogsService in quella matrice.

//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(Mangusta).

Installa mangusta eseguendo,

npm install --save @nestjs/mongoose mongoose

Dopo l'installazione, importa {MongooseModule} da '@nestjs/mongoose’ nel tuo app.module.ts file. Quindi prendi il tuo MongoDB URI e salvalo nel tuo .env file. Ripeti i passaggi per importare dotenv in app.module.ts file. Quindi nelle imports array chiama .forRoot() metodo che accetta il tuo MongoDB URI come argomento nel MongooseModule . Simile a mongoose.connect() nelle normali app express.

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

Creazione di uno schema.

Creiamo uno schema per definire la forma dei blog nella nostra collezione. Per fare questo,

  • Crea una cartella all'interno dei tuoi blogs cartella, denominarla schemas ,
  • All'interno degli schemas cartella, crea un file e chiamalo blogs.schema.ts .

Allora,

In primo luogo, dovrai,

  • Importa il prop decoratore, lo Schema decoratore e SchemaFactory da @nestjs/mongoose ,
  • Crea una classe Blog ed esportarlo,
  • Trasforma la classe in uno Schema inserendo @Schema() decoratore sopra la classe,
  • Crea un BlogSchema costante , assegna il valore di ritorno della chiamata a .createForClass(Blog) con il nome della tua classe come argomento su SchemaFactory che hai importato in precedenza.
//blogs.schema.ts

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

@Schema()
export class Blog {}

export const BlogSchema = SchemaFactory.createForClass(Blog);

Quindi dovrai definire le proprietà dello Schema.

Per definire una proprietà nello schema dovrai contrassegnare ciascuna di esse con il @prop() decoratore. Il @prop decorator accetta un oggetto options o una dichiarazione di tipo complesso. Le dichiarazioni di tipo complesso potrebbero essere matrici e dichiarazioni di tipi di oggetti nidificati.

//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);

Prossima importazione { Document } da 'mongoose' .

Quindi crea un tipo di unione con la classe Schema e il Document importato . Così,

//blogs.schema.ts

import { Document } from 'mongoose';

export type BlogDocument = Blog & Document;

Il tuo blogs.schema.ts finale il file dovrebbe assomigliare a questo,

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 di registrazione

Dovrai importare tutto nel tuo blogs.module.ts file. Per raggiungere questo obiettivo dovrai,

  • Importa {MongooseModule} da '@nestjs/mongoose’ ,
  • Importa {Blog, BlogSchema} da './schemas/blogs.schema’
  • Crea un imports array all'interno del @module decoratore
  • Chiama il .forFeature() metodo sul MongooseModule . Questo accetta un array contenente un oggetto che definisce un name e uno schema proprietà che dovrebbe essere impostata sul tuo Blog.name e il tuo BlogSchema rispettivamente.
@Module({
  imports: [
    MongooseModule.forFeature([{ name: Blog.name, schema: BlogSchema }]),
  ],

Schema di iniezione

Dovrai inserire il Blog modello nel blogs.service.ts usando il @InjectModel() decoratore. Per raggiungere questo obiettivo dovrai

  • importa { Model } da 'mongoose' ,
  • importa { InjectModel } da '@nestjs/mongoose’ ,
  • Importa {Blog, BlogDocument} da './schemas/blogs.schema’ ,
  • Crea un constructor all'interno del BlogsService classe,
  • Dichiara un private variabile e chiamala blogModel e assegna un tipo di Model<BlogDocument> ad esso. Tutti i metodi mangusta verranno chiamati su questa variabile.

Ricordalo, BlogDocument è il tipo di unione del Blog classe e il Model di Mongoose che hai creato in precedenza. Viene utilizzato come tipo generico per la tua variabile.

  • Decora blogModel con @InjectModel() e passa Blog.name come argomento.
constructor(
    @InjectModel(Blog.name)
    private blogModel: Model<BlogDocument>,
  ) {}

Come funziona il percorso

Ormai avrai notato che il @Controller decorator ha la stringa 'blogs' passato in esso. Ciò significa che il controller invierà tutte le risposte e gestirà tutte le richieste effettuate su http://localhost/3000/blogs .

Successivamente implementerai il servizio e la logica del controller.

Logica di servizio e controller.

È finalmente giunto il momento di implementare la tua funzionalità CRUD.

Prima di iniziare dovrai configurare il controller. Inizia importando alcuni HTTP decoratori di metodi nel tuo controller.

//blogs.controller.ts

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

Quindi, dovrai importare il servizio e registrarlo in modo da poterlo accedere e importare l'interfaccia per il controllo del tipo.

//blogs.controller.ts

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

Per registrare il tuo servizio crea un constructor all'interno del BlogsController classe e dichiarare un private readonly variabile service e impostane il tipo su BlogsService .

constructor(private readonly service: BlogsService) {}

Ora che sei pronto, iniziamo.

Crea

Logica di servizio

Importa { BlogsInterface } da './blogs.interface' e aggiungi un async funzione al BlogsService classe chiamata createBlog , che prenderà un parametro blogs , con il suo tipo come BlogInterface e il suo tipo restituito come Promise con un generico <Blog> genere.

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

Logica del controller

Nel tuo BlogsController classe aggiungi un async funzione alla classe. Chiamalo createBlog e contrassegnalo con il @Post decoratore che lo definisce come POST richiesta.createBlog accetta un parametro blogs , con il suo tipo come BlogInterface . Contrassegna il parametro con @Body decoratore che estrae l'intero body oggetto dal req oggetto e popola il parametro decorato con il valore di body .

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

Leggi

Aggiungi due async metodi, uno per restituire un singolo post del blog e il secondo per restituire tutti i post del blog.

Logica di servizio

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

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

Logica del controller

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

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

Il async le funzioni sono contrassegnate da @Get decoratore che lo definisce come GET richiesta.

Il secondo async il decoratore della funzione ha un argomento ':id' . Che è ciò che passerai nel @Param decoratore. Il parametro è contrassegnato da @Param('id') che estrae i params proprietà dal req oggetto e popola il parametro decorato con il valore di params .

Aggiorna

Implementiamo la logica per il PUT richiesta.

Logica di servizio

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

Logica del controller

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

Il async il secondo parametro della funzione è contrassegnato da @Body() decoratore che estrae l'intero body oggetto dal req oggetto e popola il parametro decorato con il valore di body .

Elimina

Implementiamo la logica per delete richieste.

Logica di servizio

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

La Promise il tipo generico è void perché un Delete richiesta restituisce una promessa vuota.

Logica del controller

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

Testare l'API

Per testare questa API, dovresti utilizzare uno strumento di test API. Per questo articolo, utilizzerò un popolare strumento di test API chiamato Postman. Userò dati casuali su argomenti popolari da testare.

Crea

Crea un POST richiesta a http://localhost/3000/blogs con i seguenti oggetti JSON, questo aggiungerà tutti i dati al tuo database.

{
  "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"
}

Dovresti ottenere un 201 risposta e il blog creato con una data e un _id aggiunto.

Leggi

Crea un GET richiesta a http://localhost/3000/blogs . Questo dovrebbe restituire un

200 risposta con una matrice di tutti i dati che hai aggiunto in precedenza. Copia il _id proprietà di uno degli oggetti dell'array.

Crea un altro GET richiesta a http://localhost/3000/blogs/id con l'ID precedentemente copiato. Questo dovrebbe restituire un 200 risposta con i dati dell'oggetto il cui id è stato utilizzato per effettuare la richiesta.

Aggiorna

Crea un PUT richiesta a http://localhost/3000/blogs/id con i dati sottostanti. Il id dovrebbe essere sostituito con quello che hai copiato in precedenza. Questo dovrebbe restituire un 200 risposta e aggiorna l'oggetto con l'id dietro le quinte. se esegui un altro GET richiesta dovresti ottenere l'oggetto aggiornato.

{
  "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"
}

Elimina

Crea un DELETE richiesta a http://localhost/3000/blogs/id .Questo dovrebbe restituire un 200 risposta ed elimina l'oggetto con l'id dietro le quinte. se esegui un altro GET richiesta non vedrai l'oggetto eliminato.

Conclusione

Quindi siamo finalmente alla fine di questo articolo. Ricapitoliamo ciò che hai trattato.

  • Cos'è NestJS
  • Terminologie in NestJS,
  • Creazione di un'app NestJS,
  • Integrazione di MongoDB in un'app NestJS,
  • App di manipolazione e NestJS

È parecchio, congratulazioni per essere arrivato così lontano.

Puoi trovare il codice su github.

Buona fortuna per il tuo viaggio NestJS!