Pourquoi GraphQL : guide complet ?
Dans un monde où les API REST sont omniprésentes, il est souvent difficile d'éviter la surconsommation de données et la performance dégradée. Les développeurs cherchent constamment des moyens efficaces de récupérer exactement les données dont ils ont besoin, sans avoir à se battre avec une multitude de requêtes imbriquées et inefficaces. C'est là que GraphQL entre en jeu. Conçu pour résoudre ces problèmes, GraphQL permet aux clients d'obtenir uniquement les données dont ils ont besoin, réduisant ainsi le temps de réponse et l'utilisation du réseau.
Un cas d'usage concret peut être la récupération des informations d'un utilisateur dans une application web. Avec une API REST traditionnelle, un client pourrait avoir besoin de plusieurs requêtes pour obtenir toutes les informations nécessaires : une pour les détails de l'utilisateur, une autre pour ses publications, et encore une autre pour les images associées à ces publications. Dans le cas de GraphQL, un seul appel suffit pour récupérer exactement ce qu'il faut.
Prerequis
Avant de commencer, voici les connaissances nécessaires :
- Connaissance du langage JavaScript (Node.js)
- Familiarité avec les bases de données et leur manipulation
- Compréhension des concepts de base de GraphQL
Outils à installer :
- Node.js v14 ou plus récent
- npm (Node Package Manager)
- Un éditeur de texte préféré (VSCode, WebStorm, etc.)
Concepts fondamentaux
1. Schéma (Schema)
Le schéma est le cœur de GraphQL. Il définit l'ensemble des types d'objets et les opérations qui peuvent être effectuées sur ces objets.
## Définition du schéma
type Query {
user(id: ID!): User
}
type User {
id: ID!
name: String!
email: String!
}
2. Requête (Query)
Une requête est une demande spécifique à envoyer au serveur pour récupérer des données.
## Exemple de requête
query {
user(id: "1") {
id
name
email
}
}
3. Mutation (Mutation)
Les mutations sont utilisées pour modifier les données sur le serveur, comme créer, mettre à jour ou supprimer des enregistrements.
## Exemple de mutation
mutation {
createUser(name: "John Doe", email: "john@example.com") {
id
name
email
}
}
4. Fragments (Fragment)
Les fragments permettent d'extraire une partie réutilisable du schéma pour être utilisée dans plusieurs requêtes.
## Définition d'un fragment
fragment UserSummary on User {
id
name
}
## Utilisation du fragment dans une requête
query {
user(id: "1") {
...UserSummary
email
}
}
5. Variables (Variables)
Les variables permettent de passer des valeurs dynamiques à partir du client au serveur.
## Définition d'une requête avec des variables
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
## Exécution de la requête avec des variables
{
"id": "1"
}
Mise en pratique : projet fil rouge
Nous allons construire un mini-projet complet et réaliste : une API simple pour gérer des utilisateurs. Ce projet comprendra :
- Un serveur GraphQL
- Des mutations pour créer et modifier des utilisateurs
- Une requête pour récupérer les utilisateurs
Étape 1 : Initialisation du projet
Commencez par initialiser un nouveau projet Node.js.
mkdir graphql-user-api
cd graphql-user-api
npm init -y
Installez les dépendances nécessaires :
npm install express apollo-server-express graphql
Étape 2 : Création du schéma
Créez un fichier schema.js pour définir le schéma GraphQL.
// schema.js
const { gql } = require('apollo-server-express');
const typeDefs = gql`
type User {
id: ID!
name: String!
email: String!
}
type Query {
users: [User]
user(id: ID!): User
}
input CreateUserInput {
name: String!
email: String!
}
type Mutation {
createUser(input: CreateUserInput!): User
}
`;
module.exports = { typeDefs };
Étape 3 : Création des resolvers
Créez un fichier resolvers.js pour définir les resolvers qui gèrent les requêtes et mutations.
// resolvers.js
const users = [
{ id: '1', name: 'John Doe', email: 'john@example.com' },
{ id: '2', name: 'Jane Doe', email: 'jane@example.com' }
];
const resolvers = {
Query: {
users: () => users,
user: (_, { id }) => users.find(user => user.id === id)
},
Mutation: {
createUser: (_, { input }) => {
const newUser = { id: Date.now().toString(), ...input };
users.push(newUser);
return newUser;
}
}
};
module.exports = { resolvers };
Étape 4 : Configuration du serveur
Créez un fichier server.js pour configurer le serveur Apollo.
// server.js
const express = require('express');
const { ApolloServer } = require('apollo-server-express');
const { typeDefs, resolvers } = require('./schema');
const app = express();
const server = new ApolloServer({ typeDefs, resolvers });
server.applyMiddleware({ app });
app.listen({ port: 4000 }, () =>
console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`)
);
Étape 5 : Exécution du serveur
Exécutez le serveur à l'aide de la commande suivante :
node server.js
Accédez à http://localhost:4000/graphql pour tester les requêtes et mutations.
Erreurs frequentes et debugging
1. Erreur : Syntaxe incorrecte dans le schéma
## ❌ Mauvais
type Query {
users: [User]
user(id: ID!): User
}
## ✅ Correct
type Query {
users: [User]
user(id: ID!): User
}
2. Erreur : Variable non définie
## ❌ Mauvais
query GetUser($id) {
user(id: $id) {
id
name
email
}
}
## ✅ Correct
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
3. Erreur : Mutation non définie
## ❌ Mauvais
mutation {
createUser(name: "John Doe", email: "john@example.com") {
id
name
email
}
}
## ✅ Correct
type Mutation {
createUser(input: CreateUserInput!): User
}
input CreateUserInput {
name: String!
email: String!
}
Pour aller plus loin
1. Introspection
L'introspection est une fonctionnalité de GraphQL qui permet d'explorer le schéma du serveur.
curl 'http://localhost:4000/graphql' -X POST -H "Content-Type: application/json" -d '{"query": "{ __schema { queryType { fields { name } } mutationType { fields { name } } subscriptionType { fields { name } } types { name fields { name type { name } } } directives { name locations } } }"}'
2. Subscriptions
Les souscriptions permettent aux clients de recevoir des mises à jour en temps réel du serveur.
## Définition d'un type Subscription
type Subscription {
userAdded: User
}
## Mutation pour ajouter un utilisateur
mutation {
createUser(input: CreateUserInput!): User
}
3. Performance
Pour améliorer les performances, on peut utiliser des techniques comme :
- Indexation de la base de données
- Merging de requêtes
- Optimisation des resolvers
Défi pratique
Créez un CLI tool qui permet d'ajouter et de récupérer des utilisateurs en utilisant le serveur GraphQL que vous avez créé.