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 lescontrollers
tableau et les importations, - Supprimer la référence à
AppService
dans lesproviders
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-leschemas
, - Dans les
schemas
dossier, créez un fichier et appelez-leblogs.schema.ts
.
Ensuite,
Tout d'abord, vous devrez,
- Importer le
prop
décorateur, leSchema
décorateur et leSchemaFactory
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 surSchemaFactory
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 leMongooseModule
. Cela prend dans un tableau contenant un objet qui définit unname
et unschema
propriété qui doit être définie sur votreBlog.name
et votreBlogSchema
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 duBlogsService
classe, - Déclarer un
private
variable et appelez-lablogModel
et 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
blogModel
avec@InjectModel()
et passezBlog.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 !