sql >> Databáze >  >> NoSQL >> MongoDB

ABC NestJS:Průvodce pro začátečníky s MongoDB (Mongoose).

Co je NestJS?

NestJS je moderní framework NodeJS, který pod kapotou využívá populární frameworky NodeJS, jako jsou Express a Fastify. NestJS byl z velké části inspirován Angularem, a proto využívá modulový systém ve stylu Angular. NestJS je napsán v TypeScript, i když také podporuje nativní JavaScript.

Předpoklady

Abyste mohli postupovat podle tohoto návodu, musíte splnit následující požadavky

  • Kompetence v PostMan nebo jiném testovacím nástroji API.
  • Základní znalost aplikací NodeJS a Express.
  • Základní znalost TypeScript.
  • Kompetence v MongoDB (Mongoose).

Na vašem systému by mělo být nainstalováno následující

  • NodeJS v.14 a vyšší.
  • Kód Visual Studio (doporučeno) nebo jakékoli jiné IDE.
  • PostMan nebo jakýkoli jiný testovací nástroj API.

Běžné terminologie používané v NestJS;

Zde jsou některé z nejčastěji používaných výrazů v NestJS, se kterými se v tomto článku budete často setkávat.

Rozhraní

Rozhraní je definice typu. V důsledku toho se používá jako kontrola/vynucování typu ve funkcích, třídách atd.

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

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

humanInterface výše provádí přísnou kontrolu typu na kevin objekt. Typescript by vyvolal chybu, pokud byste přidali další pole nebo změnili typ některé z vlastností objektu.

Ovladače

Kontroloři mají na starosti přijímání příchozích požadavků a odpovídání klientovi. Řadič spolupracuje se svou přidruženou službou.

Služby

Služba je poskytovatel, který ukládá a získává data a používá se s odpovídajícím správcem.

Dekoratéři

Dekorátor je výraz vracející funkci, který přijímá target , name a property descriptor jako volitelné argumenty. Dekorátoři se píší jako @decorator-name . Obvykle jsou připojeny k deklaracím tříd, metodám a parametrům.

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

@Get dekorátor výše označí blok kódu pod ním jako GET žádost. Více o tom později.

Modul

Modul je část programu, která zpracovává konkrétní úlohu. Modul v NestJS je označen anotací třídy anotované pomocí @Module() dekoratér. Nest používá metadata poskytnutá @Module() dekoratér pro uspořádání struktury aplikace.

Instalace CLI

Chcete-li začít, musíte nainstalovat NestJS CLI ****s npm . Tento krok můžete přeskočit, pokud již máte v systému nainstalováno rozhraní NestJS CLI.

npm i -g @nestjs/cli

Tento blok kódu výše nainstaluje vnořené CLI globálně do vašeho systému.

Vytvoření nového projektu

Chcete-li vygenerovat nový projekt, spusťte nest new následovaný požadovaným názvem projektu. Pro tento článek napíšeme jednoduché blogové API s funkcí CRUD při dodržení standardů RESTful.

nest new Blog-Api

Tento příkaz vás vyzve k výběru správce balíčků, zvolte npm .

Tím se celá struktura projektu vytvoří s koncovým bodem testovacího rozhraní API, jehož port je nastaven na 3000 ve výchozím stavu. Můžete to otestovat na http://localhost:3000 po spuštění npm run start:dev příkaz, který spustí server v režimu sledování podobného tomu, co dělá nodemon v expresních aplikacích.

Po otestování koncového bodu budete muset odstranit některé z výchozích souborů, protože je již nebudete potřebovat. Chcete-li to provést;

  • otevřete složku src a uvnitř
  • smažte app.controller.spec.ts ,
  • smazat app.controller.ts ,
  • smazat app.service.ts ,
  • Otevřete app.module.ts ,
  • Odstraňte odkaz na AppController v části controllers pole a importy,
  • Odstraňte odkaz na AppService v providers pole a importy.

Možná budete muset změnit soubor README.md aby splňovaly vaše specifikace.

Váš app.module.ts soubor by měl vypadat takto,

//app.module.ts

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

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

Proměnné prostředí

Je dobrým zvykem, že některé citlivé informace ve vašem kódu by neměly být zveřejňovány. Například váš PORT a váš MongoDB URI .

Pojďme to opravit ve vašem kódu.

Při běhu terminálu

npm i dotenv

Poté vytvořte .env ve vašem adresáři a přidejte jej do .gitignore soubor. Uložte si PORT proměnnou, budete muset také uložit svůj MongoDB URI později na stejném místě. Nyní nahraďte vystavený PORT ve vašem main.ts soubor. Chcete-li to provést, importujte dotenv balíček a zavolejte .config() metoda na to.

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

Mělo by to být vaše main.ts po provedení výše uvedených kroků.

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

Generování modulů

Chcete-li vygenerovat modul NestJS pomocí rozhraní CLI NestJS, spusťte níže uvedený fragment kódu.

nest generate module blogs

Tento příkaz vytvoří blogs složku, která obsahuje blogs.module.ts soubor a registry BlogsModule ve vašem app.module.ts soubor.

Rozhraní pro generování

Pojďme vygenerovat rozhraní pomocí NestJS CLI k provedení kontroly typu objektu, který bude reprezentovat vaše blogové příspěvky. Abyste toho dosáhli, musíte nejprve cd do blogs složku, protože se doporučuje, aby byly uloženy v blízkosti objektů domény, ke kterým jsou přidruženy.

cd src/blogs

Poté spusťte níže uvedený fragment kódu a vygenerujte rozhraní.

nest generate interface blogs

tím se vytvoří blogs.interface.ts soubor. Zde budeme definovat naše rozhraní. rozhraní pojmenujeme BlogsInterface .

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

před spuštěním dalších příkazů na vašem terminálu nezapomeňte cd mimo src a zpět do kořenové složky spuštěním

cd ../..

Generování služeb a ovladačů

Budete muset vygenerovat třídu služeb pro ukládání a načítání dat a zpracovávat veškerou logiku a třídu řadiče pro zpracování všech příchozích požadavků a odchozích odpovědí.

Služba

Chcete-li vygenerovat službu, spusťte příkaz níže,

nest generate service blogs

Tento příkaz vytvoří dva soubory blogs.service.spec.ts a blogs.service.ts a zaregistruje službu u providers pole v blogs.module.ts .

Ovladač

Chcete-li vygenerovat ovladač, spusťte příkaz níže,

nest generate controller blogs

Tento příkaz vytvoří dva soubory blogs.controller.spec.ts a blogs.controller.ts a zaregistruje ovladač v controllers pole v blogs.module.ts .

Díky tomu je struktura vašich blogů téměř kompletní, stačí vytvořit BlogsService přístupné dalším částem vašeho programu. Můžete toho dosáhnout vytvořením exports pole v blogs.module.ts a registraci BlogsService v tom poli.

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

Nainstalujte mongoose spuštěním,

npm install --save @nestjs/mongoose mongoose

Po instalaci importujte {MongooseModule} od '@nestjs/mongoose’ do vašeho app.module.ts soubor. Poté si vezměte MongoDB URI a uložte jej do .env soubor. Opakujte kroky pro import dotenv v app.module.ts soubor. Poté v imports pole volání .forRoot() metoda, která vezme váš MongoDB URI jako argument na MongooseModule . Podobné jako mongoose.connect() v běžných expresních aplikacích.

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

Vytvoření schématu.

Vytvořme schéma, které definuje tvar blogů v naší sbírce. Chcete-li to provést,

  • Vytvořte složku ve svých blogs složku, pojmenujte ji schemas ,
  • Uvnitř schemas vytvořte soubor a nazvěte jej blogs.schema.ts .

Potom,

Za prvé, budete muset,

  • Importujte prop dekoratér, Schema dekoratér a SchemaFactory od @nestjs/mongoose ,
  • Vytvořte Blog třídy a exportovat,
  • Změňte třídu na schéma umístěním @Schema() dekoratér nad třídou,
  • Vytvořte konstantní BlogSchema , přiřaďte návratovou hodnotu volání .createForClass(Blog) s názvem vaší třídy jako argumentem na SchemaFactory které jste importovali dříve.
//blogs.schema.ts

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

@Schema()
export class Blog {}

export const BlogSchema = SchemaFactory.createForClass(Blog);

Poté budete muset definovat vlastnosti schématu.

Chcete-li definovat vlastnost ve schématu, musíte každou z nich označit pomocí @prop() dekoratér. @prop dekorátor přijímá objekt options nebo deklaraci komplexního typu. Deklarace komplexních typů mohou být pole a deklarace typu vnořených objektů.

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

Další import { Document } z 'mongoose' .

Poté vytvořte sjednocovací typ s třídou Schema a importovaným Document . Jako tak,

//blogs.schema.ts

import { Document } from 'mongoose';

export type BlogDocument = Blog & Document;

Vaše konečné blogs.schema.ts soubor by měl vypadat takto,

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

Registrační schéma

Vše budete muset importovat do blogs.module.ts soubor. Abyste toho dosáhli, musíte,

  • Importujte {MongooseModule} od '@nestjs/mongoose’ ,
  • Importujte {Blog, BlogSchema} z './schemas/blogs.schema’
  • Vytvořte imports pole uvnitř @module dekoratér
  • Zavolejte .forFeature() metoda na MongooseModule . To zahrnuje pole obsahující objekt, který definuje name a schema vlastnost, která by měla být nastavena na váš Blog.name a vaše BlogSchema respektive.
@Module({
  imports: [
    MongooseModule.forFeature([{ name: Blog.name, schema: BlogSchema }]),
  ],

Schéma vstřikování

Budete muset vložit Blog modelovat do blogs.service.ts pomocí @InjectModel() dekoratér. Abyste toho dosáhli, musíte

  • importovat { Model } z 'mongoose' ,
  • importujte { InjectModel } od '@nestjs/mongoose’ ,
  • Importujte {Blog, BlogDocument} z './schemas/blogs.schema’ ,
  • Vytvořte constructor uvnitř BlogsService třída,
  • Prohlásit za private proměnnou a nazvěte ji blogModel a přiřadit typ Model<BlogDocument> k tomu. Na tuto proměnnou budou volány všechny metody mongoose.

Připomeňme si to, BlogDocument je sjednocený typ Blog třídy a Model Mongoose které jste vytvořili dříve. Používá se jako obecný typ pro vaši proměnnou.

  • Ozdobte blogModel pomocí @InjectModel() a předejte Blog.name jako argument.
constructor(
    @InjectModel(Blog.name)
    private blogModel: Model<BlogDocument>,
  ) {}

Jak funguje směrování

Nyní jste si museli všimnout, že @Controller dekoratér má řetězec 'blogs' přešel do toho. To znamená, že kontrolér odešle všechny odpovědi a zpracuje všechny požadavky provedené na http://localhost/3000/blogs .

Dále implementujete logiku služeb a ovladače.

Logika služby a řadiče.

Je konečně čas implementovat vaši funkcionalitu CRUD.

Než začneme, budete muset nastavit ovladač. Začněte importem nějakého HTTP metoda dekoratérů do vašeho ovladače.

//blogs.controller.ts

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

Poté budete muset službu importovat a zaregistrovat, abyste k ní měli přístup a importovali rozhraní pro kontrolu typu.

//blogs.controller.ts

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

Chcete-li zaregistrovat svou službu, vytvořte constructor uvnitř BlogsController třídy a deklarujte private readonly proměnná service a nastavte jeho typ na BlogsService .

constructor(private readonly service: BlogsService) {}

Nyní, když je vše nastaveno, můžeme začít.

Vytvořit

Servisní logika

Importujte { BlogsInterface } z './blogs.interface' a přidejte async funkce do BlogsService třída s názvem createBlog , který převezme jeden parametr blog s typem BlogInterface a jeho návratový typ jako Promise s obecným <Blog> typ.

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

Logika řadiče

Ve vašem BlogsController třídy přidat async funkce do třídy. Říkejte tomu createBlog a označte jej pomocí @Post dekoratér, který jej definuje jako POST request.createBlog má jeden parametr blog s typem BlogInterface . Označte parametr pomocí @Body dekoratér, který vyjme celé body objekt z req objekt a vyplní dekorovaný parametr hodnotou body .

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

Číst

Přidejte dva async Metody, jedna pro vrácení jednoho blogového příspěvku a druhá pro vrácení všech blogových příspěvků.

Servisní logika

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

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

Logika řadiče

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

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

async funkce jsou označeny @Get dekoratér, který jej definuje jako GET žádost.

Druhý async dekorátor funkce má argument ':id' . Což je to, co předáte do @Param dekoratér. Parametr je označen @Param('id') který extrahuje params vlastnost z req objekt a vyplní dekorovaný parametr hodnotou params .

Aktualizovat

Pojďme implementovat logiku pro PUT žádost.

Servisní logika

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

Logika řadiče

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

async druhý parametr funkce je označen @Body() dekoratér, který vyjme celé body objekt z req objekt a vyplní dekorovaný parametr hodnotou body .

Smazat

Pojďme implementovat logiku pro delete požadavky.

Servisní logika

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

Promise generický typ je void protože Delete request vrátí prázdný slib.

Logika řadiče

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

Testování rozhraní API

Chcete-li otestovat toto rozhraní API, měli byste použít nástroj pro testování rozhraní API. Pro tento článek použiji populární testovací nástroj API s názvem Postman. K testování budu používat náhodná data o oblíbených tématech.

Vytvořit

Proveďte POST požadavek na http://localhost/3000/blogs s následujícími objekty JSON to přidá všechna data do vaší databáze.

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

Měli byste dostat 201 odpověď a vytvořený blog s datem a _id přidáno.

Číst

Proveďte GET požadavek na http://localhost/3000/blogs . To by mělo vrátit a

200 odpověď s polem všech dat, která jste dříve přidali. Zkopírujte _id vlastnost jednoho z objektů pole.

Vytvořte další GET požadavek na http://localhost/3000/blogs/id s dříve zkopírovaným ID. To by mělo vrátit 200 odpověď s daty objektu, jehož ID bylo použito k vytvoření požadavku.

Aktualizovat

Proveďte PUT požadavek na http://localhost/3000/blogs/id s níže uvedenými údaji. id by měl být nahrazen tím, který jste zkopírovali dříve. To by mělo vrátit 200 odpověď a aktualizuje objekt nesoucí id v zákulisí. pokud spustíte další GET žádost, měli byste získat aktualizovaný 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"
}

Smazat

Proveďte DELETE požadavek na http://localhost/3000/blogs/id .To by mělo vrátit 200 odpověď a odstraní objekt nesoucí id v zákulisí. pokud spustíte další GET požadavek, že smazaný objekt neuvidíte.

Závěr

Tak jsme konečně na konci tohoto článku. Pojďme si zrekapitulovat, co jste probrali.

  • Co je NestJS,
  • Terminologie v NestJS,
  • Vytvoření aplikace NestJS,
  • Integrace MongoDB do aplikace NestJS,
  • Manipulace a aplikace NestJS,

To je docela hodně, gratuluji, že jste to dotáhli tak daleko.

Kód najdete na github.

Hodně štěstí na vaší cestě NestJS!


  1. Použití AngularJs a MongoDB/Mongoose

  2. Jak přimět Redis, aby zvolil politiku vystěhování LRU pouze pro některé klíče?

  3. Dávková sada dat ze slovníku do Redis

  4. Jak implementovat MongoDB vnořený $elemMatch Query v C#