/leginorme

leginorme

Primary LanguageJavaScript

Réaliser une application monolithe avec NestJs


Apres avoir installer NestJs de manière globale :

npm i -g @nestjs/cli

on peut créer un projet en tapant la commande :

nest new project-name

Ajouter le système de templating (j'ai choisi EJS : site officiel )

npm i ejs

puis ajouter la prise en charge du templating dans le fichier main.ts , et par la suite créer les dossiers public et views à la racine (ressource)

import { NestFactory } from '@nestjs/core';
import { NestExpressApplication } from '@nestjs/platform-express';
import { join } from 'path';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(
    AppModule,
  );

  app.useStaticAssets(join(__dirname, '..', 'public'));
  app.setBaseViewsDir(join(__dirname, '..', 'views'));
  app.setViewEngine('hbs');

  await app.listen(3000);
}
bootstrap();

On peut se lancer maintenant dans la création des modules, controller et service :

Création de Module

nest g mo "nom_du_module"

Création de Controller

nest g co "nom_du_controller"

Création de service

nest g s "nom_du_service"

Pour faciliter la récupération des données via la requête http POST, on peut utiliser les DTO . Et pour cela on peut creer une classe et ajouter le packgage
class-validator et class-transformer pour le formatage de données . Pour installer c'est

npm i --save class-validator class-transformer

Puis on modifie le main.ts pour ajouter une ligne pour que le formatage soit prise en compte sur toute l'application

app.useGlobalPipes(new ValidationPipe());

Voici notre classe ayant des validations

import { IsString, IsEmail, Length, IsNotEmpty }  from "class-validator";
export class SignupDto {
    @IsString()
    @IsNotEmpty()
    @Length(5, 50)
    readonly username : string;
    @IsEmail()
    readonly email : string;
    
    @IsString()
    @IsNotEmpty()
    @Length(8, 30)
    readonly password : string;
}

exemple au niveau du controller

  @Post('/signup')
    signupPost(@Body() body : SignupDto){
        return body;
    }

On peut ajouter le service pour l'insertion des données

import { Body, Controller, Get, Post, Render} from '@nestjs/common';
import { SignupDto } from 'src/dtos/signupDto';
import { UserService } from './user.service';
@Controller('user')
export class UserController {
    constructor(private readonly userService : UserService){}
    @Get('/signup')
    @Render('user/signup')
    signup(){}
    @Get('/signin')
    @Render('user/signin')
    signin(){}
    @Post('/signup')
    signupPost(@Body() body : SignupDto){
        return this.userService.signupPost(body);
    }
}

Présentation du service

import { Injectable } from '@nestjs/common';
import { SignupDto } from 'src/dtos/signupDto';
@Injectable()
export class UserService {
    signupPost(body: SignupDto) {
        throw new Error('Method not implemented.');
    }
}

On peut par la suite utiliser une base de données avec typeorm (ressource)

npm install --save @nestjs/typeorm typeorm mysql2

Puis on va dans le module principal (app.module) de notre application pour inmport typeorm et ajouter le fichier de configuration

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './user/user.module';
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
  imports: [ TypeOrmModule.forRoot({
    type: 'mysql',
    host: 'localhost',
    port: 3306,
    username: 'root',
    password: 'root',
    database: 'test',
    entities: [],
    synchronize: true,
  }),, UserModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Pour utiliser cette base de données on doit créer des entité (les tables de notre BDD), donc je créer dans le répertoire "rsc" un répertoire nommé entities et je vais stocker les entités de mon application exemple :

import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class User {
  @PrimaryGeneratedColumn()
  readonly id: number;
  @Column({ unique : true })
  readonly username : string;
  @Column({ unique : true })
  readonly email : string;
  @Column()
  readonly password : string;
}

et par la suite de doit l'ajouter au niveau du module principal

entities: [User]

sans oublié au niveau du module dans lequel je veux l'utiliser

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from 'src/entities/user.entity';
import { UserController } from './user.controller';
import { UserService } from './user.service';
@Module({
  imports: [TypeOrmModule.forFeature([User])],
  controllers: [UserController],
  providers: [UserService]
})
export class UserModule {}

Pour hacher les mots de passe on installe le package bcrypt

npm i -D @types/bcrypt

et de l'injecter au niveau du service

import { Injectable } from '@nestjs/common';
import { SignupDto } from 'src/dtos/signupDto';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from 'src/entities/user.entity';
import * as bcrypt from 'bcrypt';

@Injectable()
export class UserService {
    constructor( @InjectRepository(User)private readonly usersRepository: Repository<User>) {}

   async signupPost(body: SignupDto) : Promise<boolean> {
       try {
           const { password } = body;
           const hash = await bcrypt.hash(password, 10)
           const user = this.usersRepository.create({...body, password : hash});
           await this.usersRepository.save(user);
           return true;
        } catch (error) {
            
        }

    }
}