MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

L'ABC de NestJS :Guide du débutant avec MongoDB (Mongoose).

Qu'est-ce que NestJS ?

NestJS est un framework NodeJS moderne qui utilise des frameworks NodeJS populaires tels que Express et Fastify sous le capot. NestJS a été largement inspiré par Angular et, par conséquent, il utilise un système de modules de style Angular. NestJS est écrit en TypeScript, bien qu'il prenne également en charge le JavaScript natif.

Prérequis

Pour suivre ce tutoriel, vous devez remplir les conditions suivantes

  • Compétence dans PostMan ou tout autre outil de test d'API.
  • Connaissance de base des applications NodeJS et Express
  • Connaissance de base de TypeScript.
  • Compétence en MongoDB (Mongoose).

Les éléments suivants doivent être installés sur votre système

  • NodeJS v.14 et supérieur.
  • Code Visual Studio (recommandé) ou tout autre IDE.
  • PostMan ou tout autre outil de test d'API.

Terminologies courantes utilisées dans NestJS ;

Voici quelques-uns des termes les plus régulièrement utilisés dans NestJS que vous rencontrerez souvent dans cet article.

Interfaces

Une interface est une définition de type. En conséquence, il est utilisé comme vérificateur/exécuteur de type dans les fonctions, les classes, etc.

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

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

L'humanInterface ci-dessus effectue une vérification de type stricte sur le kevin objet. Typescript renverrait une erreur si vous ajoutiez un autre champ ou modifiiez le type de l'une des propriétés de l'objet.

Contrôleurs

Les contrôleurs sont chargés de recevoir les demandes entrantes et de répondre au client. Un contrôleur collabore avec son service associé.

Services

Un service est un fournisseur qui stocke et récupère des données et est utilisé avec son contrôleur correspondant.

Décorateurs

Un décorateur est une expression de retour de fonction qui accepte une target , name , et property descriptor comme arguments facultatifs. Les décorateurs sont écrits sous la forme @decorator-name . Ils sont généralement attachés aux déclarations de classe, aux méthodes et aux paramètres.

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

Le @Get le décorateur ci-dessus marque le bloc de code en dessous comme un GET demande. Plus d'informations à ce sujet plus tard.

Module

Un module est une partie d'un programme qui gère une tâche particulière. Un module dans NestJS est marqué en annotant une classe annotée avec le @Module() décorateur. Nest utilise les métadonnées fournies par le @Module() décorateur pour organiser la structure de l'application.

Installation de la CLI

Pour commencer, vous devrez installer la CLI NestJS **** avec npm . Vous pouvez ignorer cette étape si la CLI NestJS est déjà installée sur votre système.

npm i -g @nestjs/cli

Ce bloc de code ci-dessus installera la CLI Nest globalement sur votre système.

Créer un nouveau projet

Pour générer un nouveau projet, exécutez nest new suivi du nom de projet souhaité. Pour cet article, nous allons écrire une API de blog simple avec la fonctionnalité CRUD tout en respectant les normes RESTful.

nest new Blog-Api

Cette commande vous invitera à sélectionner un gestionnaire de packages, choisissez npm .

Cela échafaudera ensuite l'ensemble de la structure du projet avec un point de terminaison d'API de test dont le port est défini sur 3000 par défaut. Vous pouvez le tester sur http://localhost:3000 après avoir exécuté le npm run start:dev commande qui démarrera le serveur en mode veille similaire à ce que fait nodemon dans les applications express.

Après avoir testé le point de terminaison, vous devrez supprimer certains des fichiers par défaut, car vous n'en aurez plus besoin. Pour ce faire ;

  • ouvrez le dossier src et à l'intérieur,
  • supprimer app.controller.spec.ts ,
  • supprimer app.controller.ts ,
  • supprimer app.service.ts ,
  • Ouvrez app.module.ts ,
  • Supprimer la référence à AppController dans les controllers tableau et les importations,
  • Supprimer la référence à AppService dans les providers tableau et les importations.

Vous devrez peut-être également modifier le README.md pour répondre à vos spécifications.

Votre app.module.ts le fichier devrait ressembler à ceci,

//app.module.ts

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

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

Variables environnementales

Comme bonne pratique, certaines informations sensibles de votre code ne doivent pas être rendues publiques. Par exemple votre PORT et votre MongoDB URI .

Corrigeons cela dans votre code.

Sur votre terminal run

npm i dotenv

Créez ensuite un .env fichier dans votre répertoire et ajoutez-le à votre .gitignore dossier. Enregistrez votre PORT variable, vous devrez également stocker votre MongoDB URI plus tard au même endroit. Remplacez maintenant le PORT exposé dans votre main.ts dossier. Pour cela, importez le dotenv package et appelez le .config() méthode dessus.

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

Cela devrait être votre main.ts fichier après avoir suivi les étapes ci-dessus.

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

Générer des modules

Pour générer un module NestJS à l'aide de la CLI NestJS, exécutez l'extrait de code ci-dessous.

nest generate module blogs

Cette commande crée un blogs dossier contenant un blogs.module.ts file et enregistre BlogsModule dans votre app.module.ts fichier.

Génération d'interfaces

Générons une interface à l'aide de la CLI NestJS pour effectuer la vérification de type de l'objet qui représentera vos articles de blog. Pour y parvenir, vous devez d'abord cd dans les blogs dossier car il est recommandé de les stocker à proximité des objets du domaine auxquels ils sont associés.

cd src/blogs

Exécutez ensuite l'extrait de code ci-dessous pour générer l'interface.

nest generate interface blogs

cela crée un blogs.interface.ts dossier. C'est ici que nous définirons notre interface. nous nommerons l'interface BlogsInterface .

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

avant d'exécuter d'autres commandes sur votre terminal, n'oubliez pas de cd hors du src dossier et de retour dans votre dossier racine en exécutant

cd ../..

Génération de services et de contrôleurs

Vous devrez générer une classe de service pour stocker et récupérer des données et gérer toute la logique et une classe de contrôleur pour gérer toutes les demandes entrantes et les réponses sortantes.

SAV

Pour générer un service, exécutez la commande ci-dessous,

nest generate service blogs

Cette commande crée deux fichiers le blogs.service.spec.ts et le blogs.service.ts et enregistre le service dans le providers tableau dans le blogs.module.ts .

Contrôleur

Pour générer un contrôleur, exécutez la commande ci-dessous,

nest generate controller blogs

Cette commande crée deux fichiers le blogs.controller.spec.ts et le blogs.controller.ts et enregistre le contrôleur dans le controllers tableau dans le blogs.module.ts .

Avec ceux-ci, la structure de vos blogs est presque complète, il vous suffit de créer le BlogsService accessible à d'autres parties de votre programme. Vous pouvez y parvenir en créant un exports tableau dans le blogs.module.ts fichier et enregistrement du BlogsService dans ce tableau.

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

Installez la mangouste en courant,

npm install --save @nestjs/mongoose mongoose

Après l'installation, importez {MongooseModule} de '@nestjs/mongoose’ dans votre app.module.ts dossier. Saisissez ensuite votre MongoDB URI et stockez-le dans votre .env dossier. Répétez les étapes pour importer dotenv dans le app.module.ts dossier. Puis dans les imports tableau appelle le .forRoot() méthode qui prend votre MongoDB URI comme argument sur le MongooseModule . Semblable à mongoose.connect() dans les applications express régulières.

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

Création d'un schéma.

Créons un schéma pour définir la forme des blogs de notre collection. Pour ce faire,

  • Créez un dossier dans vos blogs dossier, nommez-le schemas ,
  • Dans les schemas dossier, créez un fichier et appelez-le blogs.schema.ts .

Ensuite,

Tout d'abord, vous devrez,

  • Importer le prop décorateur, le Schema décorateur et le SchemaFactory de @nestjs/mongoose ,
  • Créer une classe Blog et l'exporter,
  • Transformez la classe en schéma en plaçant le @Schema() décorateur au-dessus de la classe,
  • Créer un BlogSchema constant , affectez la valeur de retour de l'appel du .createForClass(Blog) avec le nom de votre classe en argument sur SchemaFactory que vous avez importé précédemment.
//blogs.schema.ts

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

@Schema()
export class Blog {}

export const BlogSchema = SchemaFactory.createForClass(Blog);

Ensuite, vous devrez définir les propriétés du schéma.

Pour définir une propriété dans le schéma, vous devrez marquer chacune d'elles avec le @prop() décorateur. Le @prop le décorateur accepte un objet d'options ou une déclaration de type complexe. Les déclarations de types complexes peuvent être des tableaux et des déclarations de types d'objets imbriqués.

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

Prochaine importation { Document } de 'mongoose' .

Créez ensuite un type d'union avec la classe Schema et le Document importé . Ainsi,

//blogs.schema.ts

import { Document } from 'mongoose';

export type BlogDocument = Blog & Document;

Votre blogs.schema.ts final le fichier devrait ressembler à ceci,

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

Enregistrement du schéma

Vous devrez tout importer dans votre blogs.module.ts dossier. Pour y parvenir, vous devrez,

  • Importer {MongooseModule} de '@nestjs/mongoose’ ,
  • Importer {Blog, BlogSchema} de './schemas/blogs.schema’
  • Créer un imports tableau à l'intérieur du @module décorateur
  • Appelez le .forFeature() méthode sur le MongooseModule . Cela prend dans un tableau contenant un objet qui définit un name et un schema propriété qui doit être définie sur votre Blog.name et votre BlogSchema respectivement.
@Module({
  imports: [
    MongooseModule.forFeature([{ name: Blog.name, schema: BlogSchema }]),
  ],

Schéma d'injection

Vous devrez injecter le Blog modèle dans blogs.service.ts en utilisant @InjectModel() décorateur. Pour y parvenir, vous devrez

  • importer { Model } de 'mongoose' ,
  • importer { InjectModel } de '@nestjs/mongoose’ ,
  • Importer {Blog, BlogDocument} de './schemas/blogs.schema’ ,
  • Créer un constructor à l'intérieur du BlogsService classe,
  • Déclarer un private variable et appelez-la blogModel et attribuez un type de Model<BlogDocument> à elle. Toutes les méthodes de mangouste seront appelées sur cette variable.

Rappelez-vous que, BlogDocument est le type d'union du Blog classe et le Model Mongoose que vous avez créé précédemment. Il est utilisé comme type générique pour votre variable.

  • Décorer blogModel avec @InjectModel() et passez Blog.name comme argument.
constructor(
    @InjectModel(Blog.name)
    private blogModel: Model<BlogDocument>,
  ) {}

 Comment fonctionne le routage ?

Vous devez maintenant avoir remarqué que le @Controller le décorateur a la chaîne 'blogs' passé dedans. Cela signifie que le contrôleur enverra toutes les réponses et traitera toutes les requêtes faites sur http://localhost/3000/blogs .

Ensuite, vous implémenterez la logique du service et du contrôleur.

Logique de service et de contrôleur.

Il est enfin temps d'implémenter votre fonctionnalité CRUD.

Avant de commencer, vous devez configurer votre manette. Commencez par importer du HTTP décorateurs de méthode dans votre contrôleur.

//blogs.controller.ts

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

Ensuite, vous devrez importer le service et l'enregistrer afin de pouvoir y accéder et importer l'interface pour la vérification de type.

//blogs.controller.ts

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

Pour enregistrer votre service, créez un constructor dans le BlogsController class et déclarez un private readonly variable service et définissez son type sur BlogsService .

constructor(private readonly service: BlogsService) {}

Maintenant que tout est configuré, commençons.

Créer

Logique de service

Importer { BlogsInterface } depuis './blogs.interface' et ajoutez un async fonction au BlogsService classe appelée createBlog , qui prendra un paramètre blog , avec son type comme BlogInterface , et son type de retour en tant que Promise avec un <Blog> générique taper.

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

Logique du contrôleur

Dans votre BlogsController classe ajouter un async fonction à la classe. Appelez-le createBlog et marquez-le avec le @Post décorateur qui le définit comme un POST request.createBlog prend un paramètre blog , avec son type comme BlogInterface . Marquez le paramètre avec @Body décorateur qui extrait le body entier objet de la req object et remplit le paramètre décoré avec la valeur de body .

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

Lire

Ajouter deux async méthodes, une pour renvoyer un seul article de blog et la seconde pour renvoyer tous les articles de blog.

Logique de service

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

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

Logique du contrôleur

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

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

Le async les fonctions sont marquées avec le @Get décorateur qui le définit comme un GET demande.

Le deuxième async le décorateur de la fonction a un argument ':id' . C'est ce que vous passerez dans le @Param décorateur. Le paramètre est marqué avec le @Param('id') qui extrait les params propriété de la req objet et remplit le paramètre décoré avec la valeur de params .

Mettre à jour

Implémentons la logique pour le PUT demande.

Logique de service

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

Logique du contrôleur

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

Le async le deuxième paramètre de la fonction est marqué avec le @Body() décorateur qui extrait le body entier objet de la req object et remplit le paramètre décoré avec la valeur de body .

Supprimer

Implémentons la logique pour delete demandes.

Logique de service

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

La Promise le type générique est void car un Delete la requête renvoie une promesse vide.

Logique du contrôleur

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

Tester l'API

Pour tester cette API, vous devez utiliser un outil de test d'API. Pour cet article, j'utiliserai un outil de test d'API populaire appelé Postman. Je vais utiliser des données aléatoires sur des sujets populaires pour tester.

Créer

Faire un POST demande à http://localhost/3000/blogs avec les objets JSON suivants, cela ajoutera toutes les données à votre base de données.

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

Vous devriez obtenir un 201 réponse et le blog créé avec une date et un _id ajouté.

Lire

Faire un GET demande à http://localhost/3000/blogs . Cela devrait retourner un

200 réponse avec un tableau de toutes les données que vous avez précédemment ajoutées. Copiez le _id propriété de l'un des objets du tableau.

Faire un autre GET demande à http://localhost/3000/blogs/id avec l'identifiant précédemment copié. Cela devrait retourner un 200 réponse avec les données de l'objet dont l'id a été utilisé pour faire la requête.

Mettre à jour

Faire un PUT demande à http://localhost/3000/blogs/id avec les données ci-dessous. L'id doit être remplacé par celui que vous avez copié précédemment. Cela devrait retourner un 200 réponse et met à jour l'objet portant l'id Dans les coulisses. si vous lancez un autre GET request, vous devriez obtenir l'objet mis à jour.

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

Supprimer

Faire un DELETE demande à http://localhost/3000/blogs/id .Cela devrait retourner un 200 réponse et supprime l'objet portant l'id Dans les coulisses. si vous lancez un autre GET demande, vous ne verrez pas l'objet supprimé.

Conclusion

Nous arrivons donc enfin à la fin de cet article. Récapitulons ce que vous avez couvert.

  • Qu'est-ce que NestJS ?
  • Terminologies dans NestJS
  • Création d'une application NestJS,
  • Intégration de MongoDB dans une application NestJS,
  • Manipulation et application NestJS,

C'est beaucoup, félicitations pour être arrivé jusqu'ici.

Vous pouvez trouver le code sur github.

Bonne chance dans votre voyage NestJS !