Passer au contenu

Générateur CRUD (TypeScript uniquement)

Tout au long de la durée de vie d’un projet, lorsque nous développons de nouvelles fonctionnalités, nous devons souvent ajouter de nouvelles ressources à notre application. Ces ressources nécessitent généralement plusieurs opérations répétitives que nous devons répéter chaque fois que nous définissons une nouvelle ressource.

Introduction

Imaginons un scénario du monde réel, où nous devons exposer des points de terminaison CRUD pour 2 entités, disons les entités Utilisateur et Produit. Suivant les meilleures pratiques, pour chaque entité, nous devrions effectuer plusieurs opérations, comme suit :

  • Générer un module (nest g mo) pour garder le code organisé et établir des limites claires (regroupement des composants connexes)
  • Générer un contrôleur (nest g co) pour définir les routes CRUD (ou requêtes/mutations pour les applications GraphQL)
  • Générer un service (nest g s) pour implémenter et isoler la logique métier
  • Générer une classe/interface entité pour représenter la forme des données de la ressource
  • Générer des Objets de Transfert de Données (ou entrées pour les applications GraphQL) pour définir comment les données seront envoyées sur le réseau

C’est beaucoup d’étapes !

Pour aider à accélérer ce processus répétitif, Nest CLI fournit un générateur (schématique) qui génère automatiquement tout le code de base pour nous aider à éviter cela, et rend l’expérience du développeur beaucoup plus simple.

Générer une nouvelle ressource

Pour créer une nouvelle ressource, il suffit d’exécuter la commande suivante dans le répertoire racine de votre projet :

Fenêtre de terminal
$ nest g resource

La commande nest g resource génère non seulement tous les blocs de construction NestJS (module, service, classes de contrôleur), mais aussi une classe d’entité, des classes DTO ainsi que les fichiers de test (.spec).

Voici le fichier contrôleur généré (pour l’API REST) :

Exemple de contrôleur utilisateurs
@Controller('users')
export class UsersController {
constructor(private readonly usersService: UsersService) {}
@Post()
create(@Body() createUserDto: CreateUserDto) {
return this.usersService.create(createUserDto);
}
@Get()
findAll() {
return this.usersService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.usersService.findOne(+id);
}
@Patch(':id')
update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {
return this.usersService.update(+id, updateUserDto);
}
@Delete(':id')
remove(@Param('id') id: string) {
return this.usersService.remove(+id);
}
}

De plus, il crée automatiquement des espaces réservés pour tous les points de terminaison CRUD (routes pour les API REST, requêtes et mutations pour GraphQL, abonnements de messages pour les microservices et les passerelles WebSocket) - le tout sans avoir à lever le petit doigt.

De la même manière, si vous souhaitez générer des résolveurs pour une application GraphQL, il vous suffit de sélectionner GraphQL (code first) (ou GraphQL (schema first)) comme couche de transport.

Dans ce cas, NestJS générera une classe de résolveur au lieu d’un contrôleur API REST :

Fenêtre de terminal
$ nest g resource users
> Quel type de couche de transport utilisez-vous ? GraphQL (code first)
> Souhaitez-vous générer des points d'entrée CRUD ? Oui
> CREATE src/users/users.module.ts (224 bytes)
> CREATE src/users/users.resolver.spec.ts (525 bytes)
> CREATE src/users/users.resolver.ts (1109 bytes)
> CREATE src/users/users.service.spec.ts (453 bytes)
> CREATE src/users/users.service.ts (625 bytes)
> CREATE src/users/dto/create-user.input.ts (195 bytes)
> CREATE src/users/dto/update-user.input.ts (281 bytes)
> CREATE src/users/entities/user.entity.ts (187 bytes)
> UPDATE src/app.module.ts (312 bytes)

Nous pouvons voir ci-dessous que non seulement toutes les mutations et requêtes de code de base ont été créées, mais que tout est lié ensemble. Nous utilisons le UsersService, l’entité User, et nos DTO.

Exemple de résolveur utilisateurs
import { Resolver, Query, Mutation, Args, Int } from '@nestjs/graphql';
import { UsersService } from './users.service';
import { User } from './entities/user.entity';
import { CreateUserInput } from './dto/create-user.input';
import { UpdateUserInput } from './dto/update-user.input';
@Resolver(() => User)
export class UsersResolver {
constructor(private readonly usersService: UsersService) {}
@Mutation(() => User)
createUser(@Args('createUserInput') createUserInput: CreateUserInput) {
return this.usersService.create(createUserInput);
}
@Query(() => [User], { name: 'users' })
findAll() {
return this.usersService.findAll();
}
@Query(() => User, { name: 'user' })
findOne(@Args('id', { type: () => Int }) id: number) {
return this.usersService.findOne(id);
}
@Mutation(() => User)
updateUser(@Args('updateUserInput') updateUserInput: UpdateUserInput) {
return this.usersService.update(updateUserInput.id, updateUserInput);
}
@Mutation(() => User)
removeUser(@Args('id', { type: () => Int }) id: number) {
return this.usersService.remove(id);
}
}