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 :
$ 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) :
@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 :
$ 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.
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); }}