API GraphQL avec TypeScript : tutoriel pas à pas
GraphQL est un langage de requête pour les API qui permet aux clients de demander uniquement les données dont ils ont besoin. Combiné avec TypeScript, le typage statique permet d'éviter les erreurs dès la phase de développement et rend le code plus prévisible. Dans ce tutoriel, nous allons créer une API GraphQL complète en utilisant Apollo Server et TypeScript.
Nous aborderons : la configuration du projet, la définition du schéma et des types, l'implémentation des résolveurs, les mutations pour modifier les données et l'intégration avec une base de données (in-memory pour simplifier). À la fin de l'article, vous pourrez lancer votre propre serveur GraphQL.
1. Préparation du projet et installation des dépendances
Commençons par créer un nouveau projet Node.js et installer les paquets nécessaires.
mkdir graphql-typescript-tutorialcd graphql-typescript-tutorialnpm init -ynpm install apollo-server graphqlnpm install -D typescript @types/node ts-node nodemonCréons le fichier tsconfig.json :
{ "compilerOptions": { "target": "ES2020", "module": "commonjs", "rootDir": "./src", "outDir": "./dist", "strict": true, "esModuleInterop": true, "skipLibCheck": true }, "include": ["src/**/*"]}La structure du projet sera la suivante :
src/index.ts— point d'entréesrc/schema.ts— schéma GraphQLsrc/resolvers.ts— résolveurssrc/types.ts— types TypeScript
2. Définition des types et du schéma GraphQL
Le schéma GraphQL décrit les données disponibles et comment les interroger. Pour l'exemple, créons un système simple de gestion des utilisateurs et des publications.
Créons src/types.ts :
export interface User { id: number; name: string; email: string;}
export interface Post { id: number; title: string; content: string; authorId: number;}
export interface CreateUserInput { name: string; email: string;}
export interface CreatePostInput { title: string; content: string; authorId: number;}Créons maintenant src/schema.ts avec la définition des types GraphQL :
import { gql } from 'apollo-server';
export const typeDefs = gql` type User { id: ID! name: String! email: String! posts: [Post!]! }
type Post { id: ID! title: String! content: String! author: User! }
input CreateUserInput { name: String! email: String! }
input CreatePostInput { title: String! content: String! authorId: ID! }
type Query { users: [User!]! user(id: ID!): User posts: [Post!]! post(id: ID!): Post }
type Mutation { createUser(input: CreateUserInput!): User! createPost(input: CreatePostInput!): Post! }`;Remarque : nous utilisons les types input pour les mutations — c'est une pratique standard en GraphQL.
3. Implémentation des résolveurs avec TypeScript
Les résolveurs sont des fonctions qui renvoient les données pour chaque champ du schéma. Créons src/resolvers.ts :
import { User, Post, CreateUserInput, CreatePostInput } from './types';
// Base de données in-memorylet users: User[] = [ { id: 1, name: 'Alice', email: 'alice@example.com' }, { id: 2, name: 'Bob', email: 'bob@example.com' },];
let posts: Post[] = [ { id: 1, title: 'GraphQL Basics', content: '...', authorId: 1 }, { id: 2, title: 'TypeScript Guide', content: '...', authorId: 2 },];
let nextUserId = 3;let nextPostId = 3;
export const resolvers = { Query: { users: (): User[] => users, user: (_: unknown, args: { id: string }): User | undefined => users.find(u => u.id === Number(args.id)), posts: (): Post[] => posts, post: (_: unknown,