sql >> Database >  >> NoSQL >> MongoDB

Het ABC van NestJS:een beginnershandleiding met MongoDB (Mongoose).

Wat is NestJS?

NestJS is een modern NodeJS-framework dat onder de motorkap gebruik maakt van populaire NodeJS-frameworks zoals Express en Fastify. NestJS is grotendeels geïnspireerd door Angular en als gevolg daarvan maakt het gebruik van een Angular-stijl modulesysteem. NestJS is geschreven in TypeScript, hoewel het ook native JavaScript ondersteunt.

Vereisten

Om deze tutorial te volgen, moet je aan de volgende vereisten voldoen

  • Competentie in PostMan of een andere API-testtool.
  • Basiskennis van NodeJS- en Express-apps.
  • Basiskennis van TypeScript.
  • Competentie in MongoDB(Mongoose).

Het volgende moet op uw systeem zijn geïnstalleerd

  • NodeJS v.14 en hoger.
  • Visual Studio-code (aanbevolen) of een andere IDE.
  • PostMan of een andere API-testtool.

Veelgebruikte terminologieën in NestJS;

Hier zijn enkele van de meest gebruikte termen in NestJS die je veel zult tegenkomen in dit artikel.

Interfaces

Een interface is een typedefinitie. Als gevolg hiervan wordt het gebruikt als een typecontrole / afdwinger in functies, klassen, enz.

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

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

De humanInterface hierboven voert een strikte typecontrole uit op de kevin voorwerp. Typescript zou een foutmelding geven als u een ander veld zou toevoegen of het type van een van de objecteigenschappen zou wijzigen.

Controllers

Controllers zijn verantwoordelijk voor het ontvangen van inkomende verzoeken en het reageren op de klant. Een verwerkingsverantwoordelijke werkt samen met de bijbehorende dienst.

Diensten

Een service is een provider die gegevens opslaat en ophaalt en wordt gebruikt met de bijbehorende controller.

Decorateurs

Een decorateur is een functie-terugkerende expressie die een target . accepteert , name , en property descriptor als optionele argumenten. Decorateurs worden geschreven als @decorator-name . Ze zijn meestal gekoppeld aan klassedeclaraties, methoden en parameters.

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

De @Get decorateur hierboven markeert het codeblok eronder als een GET verzoek. Daarover later meer.

-module

Een module is een onderdeel van een programma dat een bepaalde taak afhandelt. Een module in NestJS wordt gemarkeerd door een klasse te annoteren met de @Module() decorateur. Nest gebruikt de metadata van de @Module() decorateur om de applicatiestructuur te organiseren.

De CLI installeren

Om te beginnen moet je de NestJS CLI ****met npm . installeren . Je kunt deze stap overslaan als je de NestJS CLI al op je systeem hebt geïnstalleerd.

npm i -g @nestjs/cli

Dit codeblok hierboven zal de nest CLI wereldwijd op uw systeem installeren.

Een nieuw project maken

Om een ​​nieuw project te genereren, voer nest new uit gevolgd door uw gewenste projectnaam. Voor dit artikel schrijven we een eenvoudige blog-API met CRUD-functionaliteit terwijl we ons houden aan RESTful-normen.

nest new Blog-Api

Deze opdracht zal u vragen om een ​​pakketbeheerder te selecteren, kies npm .

Dit zal dan de hele projectstructuur ondersteunen met een test-API-eindpunt waarvan de poort is ingesteld op 3000 standaard. Je kunt het testen op http://localhost:3000 na het uitvoeren van de npm run start:dev commando dat de server in de kijkmodus start, vergelijkbaar met wat nodemon doet in express-apps.

Nadat u het eindpunt hebt getest, moet u enkele van de standaardbestanden verwijderen omdat u ze niet meer nodig hebt. Om dit te doen;

  • open de src-map en naar binnen,
  • verwijder app.controller.spec.ts ,
  • verwijder app.controller.ts ,
  • verwijder app.service.ts ,
  • Open app.module.ts ,
  • Verwijder de verwijzing naar AppController in de controllers array en de invoer,
  • Verwijder de verwijzing naar AppService in de providers array en de invoer.

Mogelijk moet u ook de README.md . wijzigen om aan uw specificaties te voldoen.

Uw app.module.ts bestand zou er zo uit moeten zien,

//app.module.ts

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

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

Omgevingsvariabelen

Het is een goede gewoonte om bepaalde gevoelige informatie in uw code niet openbaar te maken. Bijvoorbeeld uw PORT en uw MongoDB URI .

Laten we dit in je code oplossen.

Op uw terminal uitvoeren

npm i dotenv

Maak vervolgens een .env bestand in je directory en voeg het toe aan je .gitignore het dossier. Bewaar uw PORT variabele, moet u ook uw MongoDB URI . opslaan later op dezelfde plaats. Vervang nu de blootgestelde PORT in uw main.ts het dossier. Importeer hiervoor de dotenv pakket en roep de .config() methode erop.

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

Dit moet uw main.ts . zijn bestand nadat u de bovenstaande stappen hebt gevolgd.

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

Modules genereren

Voer het onderstaande codefragment uit om een ​​NestJS-module te genereren met behulp van de NestJS CLI.

nest generate module blogs

Deze opdracht maakt een blogs map die een blogs.module.ts . bevat bestand en registreert BlogsModule in uw app.module.ts bestand.

Interfaces genereren

Laten we een interface genereren met behulp van de NestJS CLI om de typecontrole uit te voeren voor het object dat uw blogposts vertegenwoordigt. Om dit te bereiken moet je eerst cd in de blogs map omdat het wordt aanbevolen ze op te slaan in de buurt van de domeinobjecten waaraan ze zijn gekoppeld.

cd src/blogs

Voer vervolgens het onderstaande codefragment uit om de interface te genereren.

nest generate interface blogs

dit creëert een blogs.interface.ts het dossier. Dit is waar we onze interface zullen definiëren. we noemen de interface BlogsInterface .

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

Denk eraan om cd . te doen voordat u meer opdrachten op uw terminal uitvoert uit de src map en terug naar uw hoofdmap door uit te voeren

cd ../..

Diensten en controllers genereren

U moet een serviceklasse genereren om gegevens op te slaan en op te halen en alle logica en een controllerklasse af te handelen om alle inkomende verzoeken en uitgaande reacties af te handelen.

Dienst

Voer de onderstaande opdracht uit om een ​​service te genereren,

nest generate service blogs

Met deze opdracht worden twee bestanden gemaakt, de blogs.service.spec.ts en de blogs.service.ts en registreert de dienst bij de providers array in de blogs.module.ts .

Controller

Voer de onderstaande opdracht uit om een ​​controller te genereren,

nest generate controller blogs

Deze opdracht maakt twee bestanden de blogs.controller.spec.ts en de blogs.controller.ts en registreert de controller in de controllers array in de blogs.module.ts .

Hiermee is je blogstructuur bijna compleet, je hoeft alleen maar de BlogsService . te maken toegankelijk zijn voor andere delen van uw programma. U kunt dit bereiken door een exports . aan te maken array in de blogs.module.ts bestand en het registreren van de BlogsService in dat rijtje.

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

Installeer mangoest door te rennen,

npm install --save @nestjs/mongoose mongoose

Importeer na de installatie {MongooseModule} van '@nestjs/mongoose’ in uw app.module.ts het dossier. Pak dan je MongoDB URI en sla het op in uw .env het dossier. Herhaal de stappen om dotenv . te importeren in de app.module.ts het dossier. Dan in de imports array roept de .forRoot() . aan methode die uw MongoDB URI . neemt als argument op de MongooseModule . Vergelijkbaar met de mongoose.connect() in reguliere express-apps.

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

Een schema maken.

Laten we een schema maken om de vorm van de blogs in onze collectie te definiëren. Om dit te doen,

  • Maak een map in uw blogs map, noem het schemas ,
  • Binnen de schemas map, maak een bestand en noem het blogs.schema.ts .

Dan,

Ten eerste moet je,

  • Importeer de prop binnenhuisarchitect, het Schema decorateur, en de SchemaFactory van @nestjs/mongoose ,
  • Maak een klas Blog en exporteer het,
  • Verander de klas in een Schema door de @Schema() . te plaatsen binnenhuisarchitect boven de klas,
  • Maak een constante BlogSchema , wijs de retourwaarde toe van het aanroepen van de .createForClass(Blog) met de naam van je klas als argument op SchemaFactory die je eerder hebt geïmporteerd.
//blogs.schema.ts

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

@Schema()
export class Blog {}

export const BlogSchema = SchemaFactory.createForClass(Blog);

Vervolgens moet u de eigenschappen van het schema definiëren.

Om een ​​eigenschap in het schema te definiëren, moet je ze allemaal markeren met de @prop() decorateur. De @prop decorateur accepteert een optie-object of een complexe typeverklaring. De complexe typedeclaraties kunnen arrays en geneste objecttypedeclaraties zijn.

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

Volgende import { Document } van 'mongoose' .

Maak vervolgens een unietype met de Schema-klasse en het geïmporteerde Document . zoals zo,

//blogs.schema.ts

import { Document } from 'mongoose';

export type BlogDocument = Blog & Document;

Je laatste blogs.schema.ts bestand zou er zo uit moeten zien,

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 registreren

Je moet alles importeren in je blogs.module.ts het dossier. Om dit te bereiken moet je,

  • Importeer {MongooseModule} van '@nestjs/mongoose’ ,
  • Importeer {Blog, BlogSchema} van './schemas/blogs.schema’
  • Maak een imports array binnen de @module binnenhuisarchitect
  • Bel de .forFeature() methode op de MongooseModule . Dit neemt een array in met een object dat een name definieert en een schema eigenschap die moet worden ingesteld op uw Blog.name en je BlogSchema respectievelijk.
@Module({
  imports: [
    MongooseModule.forFeature([{ name: Blog.name, schema: BlogSchema }]),
  ],

Schema injecteren

U moet de Blog . injecteren model in de blogs.service.ts met behulp van de @InjectModel() decorateur. Om dit te bereiken moet je

  • importeer { Model } van 'mongoose' ,
  • importeer { InjectModel } van '@nestjs/mongoose’ ,
  • Importeer {Blog, BlogDocument} van './schemas/blogs.schema’ ,
  • Maak een constructor binnen de BlogsService klas,
  • Declareer een private variabele en noem het blogModel en wijs een type Model<BlogDocument> . toe ernaar toe. Alle mangoestmethoden worden op deze variabele aangeroepen.

Bedenk dat, BlogDocument is het verenigingstype van de Blog klasse en het Mongoose Model die u eerder hebt gemaakt. Het wordt gebruikt als het generieke type voor uw variabele.

  • Versier blogModel met @InjectModel() en geef Blog.name door als argument.
constructor(
    @InjectModel(Blog.name)
    private blogModel: Model<BlogDocument>,
  ) {}

Hoe routering werkt

Het zal je inmiddels zijn opgevallen dat de @Controller decorateur heeft de string 'blogs' erin overgegaan. Dit betekent dat de controller alle antwoorden verzendt en alle verzoeken afhandelt die zijn gedaan op http://localhost/3000/blogs .

Vervolgens implementeer je de service- en controllerlogica.

Service- en controllerlogica.

Het is eindelijk tijd om uw CRUD-functionaliteit te implementeren.

Voordat we aan de slag gaan, moet je je controller instellen. Begin met het importeren van een aantal HTTP methode decorateurs in uw controller.

//blogs.controller.ts

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

Vervolgens moet u de service importeren en registreren, zodat u er toegang toe hebt en de interface kunt importeren voor typecontrole.

//blogs.controller.ts

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

Om uw service te registreren, maakt u een constructor in de BlogsController class en declareer een private readonly variabele service en stel het type in op BlogsService .

constructor(private readonly service: BlogsService) {}

Nu je helemaal klaar bent, gaan we aan de slag.

Maken

Servicelogica

Importeer { BlogsInterface } van './blogs.interface' en voeg een async toe functie naar de BlogsService klasse genaamd createBlog , waarvoor één parameter blog . nodig is , met als type BlogInterface , en het retourtype als een Promise met een generieke <Blog> type.

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

Controllerlogica

In je BlogsController class voeg een async toe functie voor de klas. Noem het createBlog en markeer het met de @Post decorateur die het definieert als een POST request.createBlog neemt één parameter blog , met als type BlogInterface . Markeer de parameter met @Body decorateur die de hele body . extraheert object van de req object en vult de versierde parameter met de waarde van body .

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

Lees

Voeg twee async . toe methoden, een om een ​​enkele blogpost te retourneren en de tweede om alle blogposts te retourneren.

Servicelogica

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

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

Controllerlogica

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

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

De async functies zijn gemarkeerd met de @Get decorateur die het definieert als een GET verzoek.

De tweede async de decorateur van de functie heeft een argument ':id' . Dat is wat u doorgeeft aan de @Param decorateur. De parameter is gemarkeerd met de @Param('id') die de params . extraheert eigenschap van de req object en vult de versierde parameter met de waarde van params .

Bijwerken

Laten we de logica implementeren voor de PUT verzoek.

Servicelogica

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

Controllerlogica

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

De async de tweede parameter van de functie is gemarkeerd met de @Body() decorateur die de hele body . extraheert object van de req object en vult de versierde parameter met de waarde van body .

Verwijderen

Laten we de logica voor delete implementeren verzoeken.

Servicelogica

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

De Promise generiek type is void omdat een Delete verzoek retourneert een loze belofte.

Controllerlogica

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

De API testen

Om deze API te testen, moet u een API-testtool gebruiken. Voor dit artikel gebruik ik een populaire API-testtool genaamd Postman. Ik gebruik willekeurige gegevens over populaire onderwerpen om te testen.

Maken

Maak een POST verzoek aan http://localhost/3000/blogs met de volgende JSON-objecten, zal dit alle gegevens aan uw database toevoegen.

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

Je zou een 201 . moeten krijgen reactie en de gemaakte blog met een datum en een _id toegevoegd.

Lees

Maak een GET verzoek aan http://localhost/3000/blogs . Dit zou een

. moeten opleveren

200 antwoord met een array van alle gegevens die u eerder hebt toegevoegd. Kopieer de _id eigenschap van een van de array-objecten.

Maak nog een GET verzoek aan http://localhost/3000/blogs/id met de eerder gekopieerde id. Dit zou een 200 . moeten opleveren antwoord met de gegevens van het object waarvan de id is gebruikt om het verzoek te doen.

Bijwerken

Maak een PUT verzoek aan http://localhost/3000/blogs/id met onderstaande gegevens. De id moet worden vervangen door degene die u eerder hebt gekopieerd. Dit zou een 200 . moeten opleveren antwoord en werkt het object bij met de id Achter de schermen. als je een andere GET . uitvoert verzoek moet u het bijgewerkte object krijgen.

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

Verwijderen

Maak een DELETE verzoek aan http://localhost/3000/blogs/id .Dit zou een 200 moeten opleveren antwoord en verwijdert het object met de id Achter de schermen. als je een andere GET . uitvoert verzoek zult u het verwijderde object niet zien.

Conclusie

Dus we zijn eindelijk aan het einde van dit artikel. Laten we samenvatten wat je hebt behandeld.

  • Wat NestJS is,
  • Terminologieën in NestJS,
  • Een NestJS-app maken,
  • MongoDB integreren in een NestJS-app,
  • Manipuleren en NestJS-app,

Dat is best veel, gefeliciteerd dat je zo ver bent gekomen.

Je kunt de code vinden op github.

Veel succes op je NestJS-reis!


  1. Redis:nieuwsfeeds in lijst of gesorteerde set uitwaaieren?

  2. Hoe mongo-commando's uit te voeren via shellscripts?

  3. Twitter-achtige app met MongoDB

  4. Map/reduce gebruiken om de eigenschappen in een collectie in kaart te brengen