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

The ABCs of NestJS:A Beginner's Guide with MongoDB (Mongoose).

Hvad er NestJS?

NestJS er et moderne NodeJS-framework, der gør brug af populære NodeJS-frameworks som Express og Fastify under motorhjelmen. NestJS var i høj grad inspireret af Angular, og som et resultat anvender det et modulsystem i Angular-stil. NestJS er skrevet i TypeScript, selvom det også understøtter indbygget JavaScript.

Forudsætninger

For at følge denne vejledning skal du opfylde følgende krav

  • Kompetence i PostMan eller ethvert andet API-testværktøj.
  • Grundlæggende viden om NodeJS- og Express-apps.
  • Grundlæggende kendskab til TypeScript.
  • Kompetence i MongoDB(Mongoose).

Følgende skal være installeret på dit system

  • NodeJS v.14 og nyere.
  • Visual Studio Code (anbefales) eller enhver anden IDE.
  • PostMan eller ethvert andet API-testværktøj.

Almindelige terminologier brugt i NestJS;

Her er nogle af de mest almindeligt brugte termer i NestJS, som du vil støde på meget i denne artikel.

Grænseflader

En grænseflade er en typedefinition. Som et resultat bliver det brugt som en typekontrol/enforcer i funktioner, klasser osv.

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

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

humanInterface ovenfor udfører streng typekontrol på kevin objekt. Typescript ville give en fejl, hvis du tilføjede et andet felt eller ændrede typen af ​​en af ​​objektegenskaberne.

Controllere

Controllere er ansvarlige for at modtage indgående forespørgsler og svare på klienten. En controller samarbejder med dens tilknyttede tjeneste.

Tjenester

En tjeneste er en udbyder, der gemmer og henter data og bruges sammen med dens tilsvarende controller.

Dekoratører

En dekoratør er et funktionsreturnerende udtryk, der accepterer et target , name , og property descriptor som valgfrie argumenter. Dekoratorer skrives som @decorator-name . De er normalt knyttet til klasseerklæringer, metoder og parametre.

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

@Get decorator ovenfor markerer kodeblokken under den som en GET anmodning. Mere om det senere.

Modul

Et modul er en del af et program, der håndterer en bestemt opgave. Et modul i NestJS er markeret ved at kommentere en klasse, der er kommenteret med @Module() dekoratør. Nest bruger de metadata, der leveres af @Module() dekoratør til at organisere applikationsstrukturen.

Installation af CLI

For at komme i gang skal du installere NestJS CLI ****med npm . Du kan springe dette trin over, hvis du allerede har NestJS CLI installeret på dit system.

npm i -g @nestjs/cli

Denne kodeblok ovenfor installerer nest CLI globalt på dit system.

Oprettelse af et nyt projekt

For at generere et nyt projekt køres nest new efterfulgt af dit ønskede projektnavn. Til denne artikel vil vi skrive en simpel blog API med CRUD-funktionalitet, mens vi overholder RESTful-standarder.

nest new Blog-Api

Denne kommando vil bede dig om at vælge en pakkehåndtering, vælg npm .

Dette vil derefter stilladsere hele projektstrukturen med et test API-slutpunkt, hvis port er indstillet til 3000 som standard. Du kan teste det på http://localhost:3000 efter at have kørt npm run start:dev kommando, som starter serveren i overvågningstilstand svarende til, hvad nodemon gør i ekspres-apps.

Efter at have testet slutpunktet, bliver du nødt til at slette nogle af standardfilerne, fordi du ikke har brug for dem længere. For at gøre dette;

  • åbn src-mappen og inde,
  • slet app.controller.spec.ts ,
  • slet app.controller.ts ,
  • slet app.service.ts ,
  • Åbn app.module.ts ,
  • Fjern referencen til AppController i controllers array og importerne,
  • Fjern referencen til AppService i providers array og importerne.

Du skal muligvis også ændre README.md for at opfylde dine specifikationer.

Din app.module.ts filen skal se sådan ud,

//app.module.ts

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

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

Miljøvariabler

Som god praksis bør nogle følsomme oplysninger i din kode ikke offentliggøres. For eksempel din PORT og din MongoDB URI .

Lad os rette dette i din kode.

Kør på din terminal

npm i dotenv

Opret derefter en .env fil i din mappe og tilføj den til din .gitignore fil. Gem din PORT variabel, skal du også gemme din MongoDB URI senere samme sted. Udskift nu den synlige PORT i din main.ts fil. For at gøre dette skal du importere dotenv pakke og kald .config() metode på det.

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

Dette bør være din main.ts fil, når du har fulgt ovenstående trin.

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

Generering af moduler

For at generere et NestJS-modul ved hjælp af NestJS CLI skal du køre kodestykket nedenfor.

nest generate module blogs

Denne kommando opretter en blogs mappe, der indeholder en blogs.module.ts fil og registrerer BlogsModule i din app.module.ts fil.

Generering af grænseflader

Lad os generere en grænseflade ved hjælp af NestJS CLI til at udføre typekontrol for det objekt, der repræsenterer dine blogindlæg. For at opnå dette skal du først cd ind i blogs mappe, fordi det anbefales, at de opbevares i nærheden af ​​domæneobjekterne, som de er knyttet til.

cd src/blogs

Kør derefter kodestykket nedenfor for at generere grænsefladen.

nest generate interface blogs

dette opretter en blogs.interface.ts fil. Det er her, vi vil definere vores grænseflade. vi navngiver grænsefladen BlogsInterface .

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

før du kører flere kommandoer på din terminal, skal du huske at cd ud af src mappe og tilbage til din rodmappe ved at køre

cd ../..

Generering af tjenester og controllere

Du skal generere en serviceklasse for at gemme og hente data og håndtere al logikken og en controllerklasse til at håndtere alle indgående anmodninger og udgående svar.

Service

For at generere en tjeneste skal du køre kommandoen nedenfor,

nest generate service blogs

Denne kommando opretter to filer, blogs.service.spec.ts og blogs.service.ts og registrerer tjenesten i providers array i blogs.module.ts .

Controller

For at generere en controller skal du køre kommandoen nedenfor,

nest generate controller blogs

Denne kommando opretter to filer, blogs.controller.spec.ts og blogs.controller.ts og registrerer controlleren i controllers array i blogs.module.ts .

Med disse er din blogstruktur næsten komplet, du skal bare lave BlogsService tilgængelig for andre dele af dit program. Du kan opnå dette ved at oprette en exports array i blogs.module.ts fil og registrering af BlogsService i det 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).

Installer mongoose ved at køre,

npm install --save @nestjs/mongoose mongoose

Efter installationen skal du importere {MongooseModule} fra '@nestjs/mongoose’ ind i din app.module.ts fil. Grib derefter din MongoDB URI og gem det i din .env fil. Gentag trinene for at importere dotenv i app.module.ts fil. Derefter i imports array kalder .forRoot() metode, som tager din MongoDB URI som et argument på MongooseModule . Svarende til mongoose.connect() i almindelige ekspres-apps.

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

Oprettelse af et skema.

Lad os oprette et skema til at definere formen på bloggene i vores samling. For at gøre dette,

  • Opret en mappe i dine blogs mappe, navngiv den schemas ,
  • Inde i schemas mappe, opret en fil og kald den blogs.schema.ts .

Så,

For det første skal du,

  • Importer prop dekorator, Schema decorator og SchemaFactory fra @nestjs/mongoose ,
  • Opret en klasse Blog og eksporter det,
  • Gør klassen til et skema ved at placere @Schema() dekoratør over klassen,
  • Opret et konstant BlogSchema , tildel returværdien for at kalde .createForClass(Blog) med navnet på din klasse som argument på SchemaFactory som du importerede tidligere.
//blogs.schema.ts

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

@Schema()
export class Blog {}

export const BlogSchema = SchemaFactory.createForClass(Blog);

Derefter skal du definere egenskaberne for skemaet.

For at definere en egenskab i skemaet skal du markere hver af dem med @prop() dekoratør. @prop dekoratør accepterer et optionobjekt eller en kompleks typeerklæring. De komplekse typeerklæringer kunne være arrays og indlejrede objekttypeerklæringer.

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

Næste import { Document } fra 'mongoose' .

Opret derefter en unionstype med Schema-klassen og det importerede Document . Ligesom,

//blogs.schema.ts

import { Document } from 'mongoose';

export type BlogDocument = Blog & Document;

Dine sidste blogs.schema.ts filen skal se sådan ud,

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

Registrering af skema

Du skal importere alt til din blogs.module.ts fil. For at opnå dette skal du,

  • Importer {MongooseModule} fra '@nestjs/mongoose’ ,
  • Importer {Blog, BlogSchema} fra './schemas/blogs.schema’
  • Opret en imports array inde i @module dekoratør
  • Kald .forFeature() metode på MongooseModule . Dette tager et array ind, der indeholder et objekt, der definerer et name og et schema egenskab, som skal indstilles til dit Blog.name og dit BlogSchema hhv.
@Module({
  imports: [
    MongooseModule.forFeature([{ name: Blog.name, schema: BlogSchema }]),
  ],

Injektionsskema

Du skal injicere Blog model til blogs.service.ts ved hjælp af @InjectModel() dekoratør. For at opnå dette skal du

  • importer { Model } fra 'mongoose' ,
  • importer { InjectModel } fra '@nestjs/mongoose’ ,
  • Importer {Blog, BlogDocument} fra './schemas/blogs.schema’ ,
  • Opret en constructor inde i BlogsService klasse,
  • Erklær en private variabel og kald den blogModel og tildel en type Model<BlogDocument> til det. Alle mongoose-metoder vil blive kaldt på denne variabel.

Husk det, BlogDocument er foreningstypen for Blog klasse og Mongoose Model som du har oprettet tidligere. Den bruges som generisk type for din variabel.

  • Dekorer blogModel med @InjectModel() og send Blog.name som et argument.
constructor(
    @InjectModel(Blog.name)
    private blogModel: Model<BlogDocument>,
  ) {}

Sådan fungerer routing

Nu må du have bemærket, at @Controller decorator har strengen 'blogs' gik ind i det. Det betyder, at controlleren sender alle svar og håndterer alle anmodninger på http://localhost/3000/blogs .

Dernæst skal du implementere service- og controllerlogikken.

Service- og controllerlogik.

Det er endelig tid til at implementere din CRUD-funktionalitet.

Før vi går i gang, skal du konfigurere din controller. Start med at importere noget HTTP metode dekoratorer ind i din controller.

//blogs.controller.ts

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

Derefter skal du importere tjenesten og registrere den, så du kan få adgang til den og importere grænsefladen til typekontrol.

//blogs.controller.ts

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

For at registrere din tjeneste skal du oprette en constructor inde i BlogsController klasse og erklære en private readonly variabel service og indstil dens type til BlogsService .

constructor(private readonly service: BlogsService) {}

Nu hvor du er klar, lad os komme i gang.

Opret

Servicelogik

Importer { BlogsInterface } fra './blogs.interface' og tilføje en async funktion til BlogsService klasse kaldet createBlog , som tager én parameter Blog , med dens type som BlogInterface , og dens returtype som et Promise med en generisk <Blog> type.

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

Controller Logic

I din BlogsController klasse tilføje en async funktion til klassen. Kald det createBlog og marker det med @Post dekorator, der definerer det som en POST anmodning.createBlog tager én parameter Blog , med dens type som BlogInterface . Marker parameteren med @Body dekorator, som udtrækker hele body objekt fra req objekt og udfylder den dekorerede parameter med værdien body .

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

Læs

Tilføj to async metoder, en til at returnere et enkelt blogindlæg og den anden til at returnere alle blogindlæg.

Servicelogik

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

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

Controller Logic

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

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

async funktioner er markeret med @Get dekorator, der definerer det som en GET anmodning.

Den anden async funktions dekorator har et argument ':id' . Hvilket er, hvad du vil overføre til @Param dekoratør. Parameteren er markeret med @Param('id') som udtrækker params egenskab fra req objekt og udfylder den dekorerede parameter med værdien params .

Opdatering

Lad os implementere logikken for PUT anmodning.

Servicelogik

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

Controller Logic

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

async funktions anden parameter er markeret med @Body() dekorator, som udtrækker hele body objekt fra req objekt og udfylder den dekorerede parameter med værdien body .

Slet

Lad os implementere logikken for delete anmodninger.

Servicelogik

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

Promise generisk type er void fordi en Delete anmodning returnerer et tomt løfte.

Controller Logic

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

Test af API

For at teste denne API skal du bruge et API-testværktøj. Til denne artikel vil jeg bruge et populært API-testværktøj kaldet Postman. Jeg vil bruge tilfældige data om populære emner til at teste.

Opret

Lav en POST anmodning til http://localhost/3000/blogs med følgende JSON-objekter vil dette tilføje alle data til din 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"
}

Du bør få en 201 svar og den oprettede blog med en dato og et _id tilføjet.

Læs

Lav en GET anmodning til http://localhost/3000/blogs . Dette skulle returnere en

200 svar med en række af alle de data, du tidligere har tilføjet. Kopiér _id egenskab for et af array-objekterne.

Lav endnu en GET anmodning til http://localhost/3000/blogs/id med det tidligere kopierede id. Dette skulle returnere en 200 svar med dataene for det objekt, hvis id blev brugt til at lave anmodningen.

Opdatering

Lav en PUT anmodning til http://localhost/3000/blogs/id med nedenstående data. id bør erstattes med den, du kopierede tidligere. Dette skulle returnere en 200 svar og opdaterer objektet, der bærer id bag scenen. hvis du kører en anden GET anmode om, at du skal få det opdaterede objekt.

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

Slet

Lav en DELETE anmodning til http://localhost/3000/blogs/id .Dette skulle returnere en 200 svar og sletter objektet, der bærer id bag scenen. hvis du kører en anden GET anmode om, at du ikke vil se det slettede objekt.

Konklusion

Så er vi endelig ved slutningen af ​​denne artikel. Lad os opsummere, hvad du har dækket.

  • Hvad NestJS er,
  • Terminologier i NestJS,
  • Oprettelse af en NestJS-app,
  • Integration af MongoDB i en NestJS-app,
  • Manipulation og NestJS-app,

Det er ret meget, tillykke med at du er nået så langt.

Du kan finde koden på github.

Held og lykke på din NestJS-rejse!


  1. MongoDB - få dokumenter med max attribut per gruppe i en samling

  2. Oprettelse af et administrationsområde på fem minutter med AdminBro, express, mongoDB, mongoose

  3. Top 5 fordele ved Shared MongoDB Hosting

  4. mongo.so:> udefineret symbol:php_json_encode i Ukendt på linje 0. Efter installation mongo driver til php