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 https://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 à
AppControllerdans lescontrollerstableau et les importations, - Supprimer la référence à
AppServicedans lesproviderstableau 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
blogsdossier, nommez-leschemas, - Dans les
schemasdossier, créez un fichier et appelez-leblogs.schema.ts.
Ensuite,
Tout d'abord, vous devrez,
- Importer le
propdécorateur, leSchemadécorateur et leSchemaFactoryde@nestjs/mongoose, - Créer une classe
Bloget l'exporter, - Transformez la classe en schéma en plaçant le
@Schema()décorateur au-dessus de la classe, - Créer un
BlogSchemaconstant , affectez la valeur de retour de l'appel du.createForClass(Blog)avec le nom de votre classe en argument surSchemaFactoryque 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
importstableau à l'intérieur du@moduledécorateur - Appelez le
.forFeature()méthode sur leMongooseModule. Cela prend dans un tableau contenant un objet qui définit unnameet unschemapropriété qui doit être définie sur votreBlog.nameet votreBlogSchemarespectivement.
@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 duBlogsServiceclasse, - Déclarer un
privatevariable et appelez-lablogModelet attribuez un type deModel<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
blogModelavec@InjectModel()et passezBlog.namecomme 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 https://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 à https://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 à https://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 à https://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 à https://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 à https://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 !