Nouveau : Datasets open source gratuits disponibles !Decouvrir →
🟢
Intermediaire 25 min NestJS

NestJS avec TypeScript : guide complet

Pourquoi NestJS avec TypeScript : guide complet ?

NestJS est un framework d'application Node.js conçu pour créer des applications robustes et évolutives. En utilisant TypeScript, vous bénéficiez de la typisation statique, qui améliore la lisibilité, la maintenance et le débogage du code. Ce guide complète couvrira les concepts fondamentaux de NestJS avec TypeScript, ainsi qu'une mise en pratique sur un projet réel.

Prerequis

  • Connaissance de base de JavaScript ou TypeScript
  • Connaissance des concepts d'objets, de fonctions et de classes
  • Familiarité avec l'utilisation du terminal
  • Node.js et npm installés (version 12.x ou supérieure)
  • Visual Studio Code ou un autre éditeur de code

Concepts fondamentaux

1. Modules

Un module est une unité logique qui encapsule des fonctionnalités liées dans votre application.

// src/app.module.ts
import { Module } from '@nestjs/common';
import { TasksModule } from './tasks/tasks.module';

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

2. Controllers

Un controller gère les requêtes entrantes et renvoie des réponses.

// src/tasks/tasks.controller.ts
import { Controller, Get, Post, Body } from '@nestjs/common';
import { TasksService } from './tasks.service';

@Controller('tasks')
export class TasksController {
  constructor(private readonly tasksService: TasksService) {}

  @Get()
  findAll() {
    return this.tasksService.findAll();
  }

  @Post()
  create(@Body() createTaskDto: CreateTaskDto) {
    return this.tasksService.create(createTaskDto);
  }
}

3. Services

Un service contient la logique métier de l'application.

// src/tasks/tasks.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class TasksService {
  private readonly tasks: Task[] = [];

  findAll(): Task[] {
    return this.tasks;
  }

  create(task: CreateTaskDto): Task {
    this.tasks.push(task);
    return task;
  }
}

4. DTO (Data Transfer Objects)

Les DTO sont des classes utilisées pour transmettre des données entre les couches de l'application.

// src/tasks/dto/create-task.dto.ts
export class CreateTaskDto {
  title: string;
  description?: string;
}

5. Interceptors

Un interceptor peut modifier une requête ou une réponse avant qu'elle ne soit traitée par le contrôleur ou le service.

// src/tasks/interceptors/logging.interceptor.ts
import { Injectable, NestInterceptor, ExecutionContext, CallHandler } from '@nestjs/common';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    console.log('Before...');
    const now = Date.now();
    return next.handle().pipe(
      tap(() => console.log(`After... ${Date.now() - now}ms`)),
    );
  }
}

Mise en pratique : projet fil rouge

Étape 1 : Créer un nouveau projet NestJS

npm install -g @nestjs/cli
nest new task-management-api
cd task-management-api

Étape 2 : Créer une entité Task

// src/tasks/task.entity.ts
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';

@Entity()
export class Task {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  title: string;

  @Column({ nullable: true })
  description?: string;
}

Étape 3 : Créer un module pour les tâches

// src/tasks/tasks.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { TasksController } from './tasks.controller';
import { TasksService } from './tasks.service';
import { Task } from './task.entity';

@Module({
  imports: [TypeOrmModule.forFeature([Task])],
  controllers: [TasksController],
  providers: [TasksService],
})
export class TasksModule {}

Étape 4 : Créer un service pour les tâches

// src/tasks/tasks.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Task } from './task.entity';

@Injectable()
export class TasksService {
  constructor(
    @InjectRepository(Task)
    private readonly tasksRepository: Repository<Task>,
  ) {}

  findAll(): Promise<Task[]> {
    return this.tasksRepository.find();
  }

  async create(task: Partial<Task>): Promise<Task> {
    const newTask = this.tasksRepository.create(task);
    return this.tasksRepository.save(newTask);
  }
}

Étape 5 : Créer un contrôleur pour les tâches

// src/tasks/tasks.controller.ts
import { Controller, Get, Post, Body } from '@nestjs/common';
import { TasksService } from './tasks.service';
import { Task } from './task.entity';

@Controller('tasks')
export class TasksController {
  constructor(private readonly tasksService: TasksService) {}

  @Get()
  async findAll(): Promise<Task[]> {
    return this.tasksService.findAll();
  }

  @Post()
  async create(@Body() task: Partial<Task>): Promise<Task> {
    return this.tasksService.create(task);
  }
}

Étape 6 : Ajouter la base de données

Modifier le fichier ormconfig.json pour configurer la base de données.

{
  "type": "sqlite",
  "database": "db.sqlite",
  "synchronize": true,
  "entities": ["dist/**/*.entity{.ts,.js}"]
}

Étape 7 : Ajouter le middleware d'interception

// src/app.module.ts
import { Module } from '@nestjs/common';
import { APP_INTERCEPTOR } from '@nestjs/core';
import { LoggingInterceptor } from './tasks/interceptors/logging.interceptor';

@Module({
  imports: [TypeOrmModule.forRoot(), TasksModule],
  providers: [
    {
      provide: APP_INTERCEPTOR,
      useClass: LoggingInterceptor,
    },
  ],
})
export class AppModule {}

Erreurs frequentes et debugging

1. Erreur : Type 'undefined' is not assignable to type 'number'

// ❌ Mauvais
id: undefined;

// ✅ Correct
id: null;

2. Erreur : Nest can't resolve dependencies of class TasksService. Please make sure that the argument InjectableRepository(Task) at index [0] is available in the TasksModule context.

// src/tasks/tasks.service.ts
import { Injectable, InjectRepository } from '@nestjs/common';
import { Repository } from 'typeorm';
import { Task } from './task.entity';

@Injectable()
export class TasksService {
  constructor(
    @InjectRepository(Task)
    private readonly tasksRepository: Repository<Task>,
  ) {}
}

3. Erreur : Cannot find module 'typeorm'. Did you mean to set the root directory using "include"?

npm install typeorm --save

Pour aller plus loin

  1. Authentification et Sécurité : Apprenez comment ajouter une authentification JWT pour sécuriser votre API.
  2. Gestion des erreurs personnalisées : Créez un système de gestion d'erreurs personnalisé pour améliorer la qualité de l'API.
  3. Intégration avec MongoDB : Utilisez Mongoose avec NestJS pour travailler avec une base de données NoSQL.

Défi pratique

Créez un CLI tool avec NestJS qui génère automatiquement des fichiers de configuration et de modèle pour votre application.

Besoin d'aide sur NestJS ?

Besoin d'aide sur un projet technique ? Decrivez-le pour des conseils personnalises.

Recevoir des conseils

Pages liees

Chaque semaine, le meilleur de la tech francaise

Tendances, salaires, outils et opportunites — directement dans votre boite mail.

Gratuit. Desabonnement en un clic. Pas de spam.