author: Aurelien Loyer / Emmanuel Demey summary: Pendant ce codelab, nous allons créer un backend pour une application d'e-commerce avec le framework NestJS. id: docs/lab ga: UA-137363732-2 feedback link: https://twitter.com/AurelienLoyer
Pour faire ce codelab, vous avez besoin des outils suivants :
@nestjs/cli
installé globalementnpm install -g @nestjs/cli
# OU
yarn global add @nestjs/cli
step0
du repository GITgit clone -b step0 https://github.com/T3kstiil3/codelab-nestjs-corrections
cd codelab-nestjs-corrections
npm install # yarn
Si vous utilisez VSCode, nous vous proposons une selection d'extensions que vous pouvez utiliser pour un projet NestJS. Pour les lister, dans la page dédiée aux extensions, faites une recherche via le mot clé @recommanded
. Normalement VSCode listera notre liste d'extensions.
Si vous exécutez la commande suivante, votre API sera disponible à l'URL http://localhost:3000
npm run start
main.ts
, ajoutez l'intégration Swagger à l'application NestJSNous améliorerons cette intégration au fur et à mesure des TPs.
Voici de plus quelques liens qui pourraient vous être utiles tout au long de ce codelab :
git checkout step1 -f
AppController
, implementez un CRUD permettant de gérer des produits (en mémoire). Nous allons pouvoir :Un produit sera représenté par la classe TypeScript suivante :
import { ApiProperty, ApiPropertyOptions } from '@nestjs/swagger';
export class Product {
@ApiProperty({ example: 12 } as ApiPropertyOptions)
readonly id: number;
@ApiProperty({ example: 'Super product' } as ApiPropertyOptions)
readonly label?: string;
@ApiProperty({
example:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor ...',
} as ApiPropertyOptions)
readonly description?: string;
@ApiProperty({ example: '' } as ApiPropertyOptions)
readonly image?: string;
@ApiProperty({ example: 15.0 } as ApiPropertyOptions)
readonly price?: number;
@ApiProperty({ example: 5 } as ApiPropertyOptions)
readonly stock?: number;
}
Un fichier products.json est à votre disposition. Il contient un jeu de données que vous pouvez utiliser pour cette API.
Voici de plus quelques liens qui pourraient vous être utiles tout au long de ce codelab :
git checkout step2 -f
Nous allons à présent créer un module NestJS afin d'y ajouter la fonctionnalité de gestion des produits.
git checkout step2 -f
ProductsModule
.nest generate module products
ProductsController
nest generate controller products
Vérifiez que ce nouveau contrôleur est bien associé au module ProductsModule
créé au début de cet exercice.
Ajoutez au module principal de votre application le module ProductsModule
.
Voici de plus quelques liens qui pourraient vous êtres utiles tout au long de ce codelab :
git checkout step3 -f
Nous allons à présent externaliser le code métier dans un service dédié que nous nommerons ProductsService
.
products
nest generate service products
Migrez tout le code métier écrit jusqu'à présent dans le contrôleur ProductsController
dans ce service.
Injectez et utilisez ce service dans le contrôleur ProductsController
.
Voici de plus quelques liens qui pourraient vous êtres utiles tout au long de ce codelab :
git checkout step4 -f
Activez la validation de manière globale pour toute l'application
Installez les modules class-validator
et class-transformer
.
Ajoutez les contraintes suivantes sur votre classe Product
id
doit être un number
label
doit être une string
description
doit être une string
, avec un taille entre 10 et 80 caractèresimage
doit être une string
, et se terminer par /\.(jpe?g|png|gif|bmp)$/
(via un custom validateur)price
doit être une number
, compris entre 0 et 100stock
doit être une entier
Pour cela, nous allons utiliser des décorateurs définis dans le module class-validator
.
Voici de plus quelques liens qui pourraient vous êtres utiles tout au long de ce codelab :
git checkout step5 -f
Normalement pas besoin d'installer de librairie de test pour cette étape.
Comme vue dans les slides, NestJs dispose déjà de @nestjs/testing
pour vous aidez à tester aux mieux votre application.
A ce stade du codelab nous avons la posibilite de tester plusieurs partie de notre application.
Commencez par tester via des tests unitaire :
ProductsService
Afin de faciliter l'écriture des tests, nous allons tout d'abord externaliser notre tableau de produits dans un nouveau provider
@Module({
controllers: [ProductsController],
providers: [
ProductsService,
{ provide: 'ProductsJson', useValue: productsJson },
],
})
@Injectable()
export class ProductsService {
private products: Product[];
constructor(
@Inject('ProductsJson') private readonly productsJson: Product[],
) {
this.products = productsJson;
}
}
ProductsController
Puis terminez par des tests e2e que nous placerons dans le dossier test/products/products.e2e-spec.ts
git checkout step6 -f
npm install @nestjs/jwt @nestjs/passport @nestjs/platform-express passport passport-jwt
users
dans lequel nous allons implémenter la gestions des utilisateurs. nest generate module users
PassportModule
et JwtModule
de la manière suivante : [
PassportModule.register({ defaultStrategy: 'jwt' }),
JwtModule.register({
secretOrPrivateKey: 'secretKey',
signOptions: {
expiresIn: 3600,
},
}),
]
Nous allons à présent créer deux service :
UsersService
pour la gestion des utilisateursJwtStrategy
pour configurer la stratégie d'authentification de notre application nest generate service users/JwtStrategy
nest generate service users/users
JwtStrategyService
aura la structure suivante :@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
constructor(private readonly usersService: UsersService) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'secretKey',
});
}
async validate(payload: JwtPayload) {
const user = await this.usersService.validateUser(payload);
if (!user) {
throw new UnauthorizedException('The user is unauthorized');
}
return user;
}
}
Dans la méthode validate
, nous allons appeler une méthode validateUser
du service UsersService
que nous allons implémenter dans le point suivant.
Si l'objet User
retourné par cet méthode n'est pas défini, vous devez émettre une exception UnauthorizedException
. Sinon vous pouvez retourner l'objet lui-même.
Dans le service UsersService
, nous allons implémenter deux méthodes :
validateUser
: cette méthode prendra en paramètre l'objet JwtPayload
et retournera une Promise<boolean>
. Le boolean
sera à true
si le duo email
et password
sont corrects. Pour cela, vous pouvez utiliser un tableau d'utilisateurs défini en mémoire (bien evidemment nous ne faisons jamais cela dans la vrai vie :p ). [
{
"id": 1,
"username": "Aurel",
"email": "aurelien@loyer.fr",
"password": "password",
"cart": {}
},
{
"id": 2,
"username": "Manu",
"email": "emmanuel@demey.fr",
"password": "password",
"cart": {}
}
]
* une méthode `login` qui prendra en paramètre l'email et le password d'un utilisateur. Après avoir vérifié que la combinaison email/password correspond bien à un utilisateur, cette méthode retournera le token JWT nécessaire pour s'authentifier. Pour cela, on utilisera le service `JwtService` du module `@nestjs/jwt`
const accessToken = this.jwtService.sign(payload);
return {
expiresIn: 3600,
accessToken: `Bearer ${accessToken}`,
};
Créez un controller users
proposant une endpoint permettant d'appeler la méthode login
du service UsersService
.
Sécurisez la route permettant de créer et mettre à jour des produits
Voici de plus quelques liens qui pourraient vous êtres utiles tout au long de ce codelab :