Introduction
\n\nGraphQL est un langage de requête pour les API qui permet aux clients d'obtenir uniquement les données nécessaires. Combiné avec TypeScript, il devient un outil puissant pour créer des API typées, évolutives et documentées. Dans ce tutoriel étape par étape, nous allons créer en pratique une API GraphQL complète en TypeScript en utilisant Apollo Server et TypeGraphQL.
Vous apprendrez :
\n- \n
- Comment configurer un projet avec TypeScript et Apollo Server \n
- Comment définir un schéma GraphQL avec les décorateurs TypeGraphQL \n
- Comment écrire des résolveurs avec un typage complet \n
- Comment connecter une base de données et exécuter des requêtes \n
Ce contenu sera utile aussi bien aux débutants qu'aux développeurs déjà familiers avec les API REST, mais souhaitant maîtriser une approche moderne de construction d'API.
\n\n1. Configuration du projet et installation des dépendances
\n\nCommençons par l'initialisation du projet. Assurez-vous d'avoir Node.js (version 16+) et npm/yarn installés.
\n\nmkdir graphql-ts-tutorial\ncd graphql-ts-tutorial\nnpm init -y\n\nInstallez les paquets nécessaires :
\n\nnpm install apollo-server graphql reflect-metadata type-graphql class-validator\nnpm install -D typescript @types/node ts-node\n\nCréez le fichier tsconfig.json :
{\n "compilerOptions": {\n "target": "ES2020",\n "module": "commonjs",\n "lib": ["ES2020"],\n "experimentalDecorators": true,\n "emitDecoratorMetadata": true,\n "strict": true,\n "esModuleInterop": true,\n "outDir": "./dist",\n "rootDir": "./src"\n },\n "include": ["src/**/*"]\n}\n\nNotez les options experimentalDecorators et emitDecoratorMetadata — elles sont nécessaires pour le fonctionnement de TypeGraphQL.
2. Définition du schéma et des types avec TypeGraphQL
\n\nCréons le dossier src et le fichier src/types/User.ts. Nous y décrirons le modèle utilisateur.
import { ObjectType, Field, ID, InputType } from "type-graphql";\n\n@ObjectType()\nexport class User {\n @Field(() => ID)\n id!: number;\n\n @Field()\n name!: string;\n\n @Field()\n email!: string;\n\n @Field()\n createdAt!: Date;\n}\n\nExplication :
\n- \n
@ObjectType()— marque la classe comme un type GraphQL. \n @Field()— indique quels champs seront disponibles dans l'API. \n @Field(() => ID)— pour le type scalaire ID. \n
Créons maintenant un InputType pour les mutations (création d'utilisateur) :
@InputType()\nexport class CreateUserInput {\n @Field()\n name!: string;\n\n @Field()\n email!: string;\n}\n\nCe type sera utilisé dans les résolveurs pour la validation des données d'entrée.
\n\n3. Écriture des résolveurs
\n\nCréons le fichier src/resolvers/UserResolver.ts. Nous y implémenterons la logique des requêtes et des mutations.
import { Resolver, Query, Mutation, Arg } from "type-graphql";\nimport { User, CreateUserInput } from "../types/User";\n\n// Simulation de base de données\nlet users: User[] = [\n { id: 1, name: "Ivan Ivanov", email: "ivan@example.com", createdAt: new Date() },\n { id: 2, name: "Maria Petrova", email: "maria@example.com", createdAt: new Date() }\n];\n\nlet nextId = 3;\n\n@Resolver()\nexport class UserResolver {\n @Query(() => [User])\n async users(): Promise<User[]> {\n return users;\n }\n\n @Query(() => User, { nullable: true })\n async user(@Arg("id") id: number): Promise<User | undefined> {\n return users.find(u => u.id === id);\n }\n\n @Mutation(() => User)\n async createUser(@Arg("data") data: CreateUserInput): Promise<User> {\n const newUser: User = {\n id: nextId++,\n name: data.name,\n email: data.email,\n createdAt: new Date()\n };\n users.push(ne