Pourquoi Next.js avec GraphQL ?
Contexte réel : En tant que développeur web, vous avez sans doute déjà travaillé sur des projets où les données doivent être récupérées et affichées en temps réel à partir de diverses sources. Avec une croissance exponentielle du nombre de composants React dans vos applications, la gestion efficace des requêtes réseau a devint un défi majeur. C'est là que GraphQL entre en jeu : il offre une solution élégante pour récupérer exactement les données nécessaires à chaque composant, réduisant ainsi le temps de réponse et améliorant l'expérience utilisateur.
Un cas d'usage concret : Imaginez un blog avec des articles, chacun ayant des commentaires associés. Avec une API REST traditionnelle, vous devriez faire au moins deux appels réseau pour récupérer les données nécessaires : un pour les articles et un autre pour les commentaires associés à chaque article. Avec GraphQL, vous pouvez effectuer tout cela dans une seule requête, ce qui améliore significativement l'efficacité et la performance.
Prerequis
Connaissances Nécéssaires :
- JavaScript avancé
- React.js
- Connaissance de base des APIs REST
- Familiarité avec les concepts de GraphQL (Schémas, Querys, Mutations)
Outils à Installer :
- Node.js (v14.0 ou plus)
- npm (Node Package Manager)
- Yarn (optionnel, mais recommandé pour gérer les dépendances)
- GraphiQL (pour tester les requêtes GraphQL)
Concepts Fondamentaux
Schéma GraphQL
Le schéma GraphQL est une description complète et précise de toutes les données disponibles dans votre API. Il définit quelles opérations sont possibles, quels types de données peuvent être récupérés et comment ils sont liés entre eux.
type Query {
articles: [Article]
}
type Article {
id: ID!
title: String!
content: String!
comments: [Comment]
}
type Comment {
id: ID!
author: String!
text: String!
}
Créer un serveur GraphQL avec Apollo Server
Pour exposer notre schéma, nous utiliserons Apollo Server.
npm install apollo-server-express express graphql
javascript
// server.js
const express = require('express');
const { ApolloServer, gql } = require('apollo-server-express');
const typeDefs = gql`
type Query {
articles: [Article]
}
type Article {
id: ID!
title: String!
content: String!
comments: [Comment]
}
type Comment {
id: ID!
author: String!
text: String!
}
`;
const resolvers = {
Query: {
articles: () => [
{ id: '1', title: 'Article 1', content: 'Content of article 1' },
{ id: '2', title: 'Article 2', content: 'Content of article 2' },
],
},
};
const server = new ApolloServer({ typeDefs, resolvers });
const app = express();
server.applyMiddleware({ app });
app.listen({ port: 4000 }, () =>
console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`)
);
Créer un client GraphQL avec Apollo Client
Pour consommer notre API dans une application Next.js, nous utiliserons Apollo Client.
npm install @apollo/client graphql
javascript
// pages/_app.js
import { ApolloProvider } from '@apollo/client';
import client from '../lib/apolloClient';
function MyApp({ Component, pageProps }) {
return (
<ApolloProvider client={client}>
<Component {...pageProps} />
</ApolloProvider>
);
}
export default MyApp;
javascript
// lib/apolloClient.js
import { ApolloClient, InMemoryCache } from '@apollo/client';
const client = new ApolloClient({
uri: 'http://localhost:4000/graphql',
cache: new InMemoryCache(),
});
export default client;
Créer une page Next.js avec GraphQL
Maintenant, nous allons créer une page Next.js qui utilise GraphQL pour récupérer et afficher les articles.
// pages/index.js
import { useQuery } from '@apollo/client';
import gql from 'graphql-tag';
const GET_ARTICLES = gql`
query GetArticles {
articles {
id
title
content
}
}
`;
export default function Home() {
const { loading, error, data } = useQuery(GET_ARTICLES);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;
return (
<div>
{data.articles.map((article) => (
<div key={article.id}>
<h2>{article.title}</h2>
<p>{article.content}</p>
</div>
))}
</div>
);
}
Mise en Pratique : Projet Fil Rouge
Mini-Projet Complet et Réaliste : Nous allons créer un simple gestionnaire de tâches. Les utilisateurs pourront ajouter, modifier et supprimer des tâches.
Étapes Numérotées avec Du Code à Chaque Étape
1. Créer le serveur GraphQL
Créez un nouveau fichier server.js :
// server.js
const express = require('express');
const { ApolloServer, gql } = require('apollo-server-express');
const typeDefs = gql`
type Task {
id: ID!
title: String!
completed: Boolean!
}
type Query {
tasks: [Task]
task(id: ID!): Task
}
type Mutation {
createTask(title: String!, completed: Boolean!): Task
updateTask(id: ID!, title: String, completed: Boolean): Task
deleteTask(id: ID!): Task
}
`;
const resolvers = {
Query: {
tasks: () => [
{ id: '1', title: 'Buy groceries', completed: false },
{ id: '2', title: 'Finish project', completed: true },
],
task: (_, { id }) => {
return { id, title: 'Task 1', completed: false };
},
},
Mutation: {
createTask: (_, { title, completed }) => {
const newTask = { id: Date.now().toString(), title, completed };
// Here you would typically add the task to a database
return newTask;
},
updateTask: (_, { id, title, completed }) => {
// Here you would typically update the task in a database
return { id, title, completed };
},
deleteTask: (_, { id }) => {
// Here you would typically remove the task from a database
return { id, title: 'Task 1', completed: false };
},
},
};
const server = new ApolloServer({ typeDefs, resolvers });
const app = express();
server.applyMiddleware({ app });
app.listen({ port: 4000 }, () =>
console.log(`🚀 Server ready at http://localhost:4000${server.graphqlPath}`)
);
2. Créer le client GraphQL
Créez un nouveau fichier lib/apolloClient.js :
// lib/apolloClient.js
import { ApolloClient, InMemoryCache } from '@apollo/client';
const client = new ApolloClient({
uri: 'http://localhost:4000/graphql',
cache: new InMemoryCache(),
});
export default client;
3. Créer une page Next.js
Créez un nouveau fichier pages/index.js :
// pages/index.js
import { useQuery, useMutation } from '@apollo/client';
import gql from 'graphql-tag';
const GET_TASKS = gql`
query GetTasks {
tasks {
id
title
completed
}
}
`;
const CREATE_TASK = gql`
mutation CreateTask($title: String!, $completed: Boolean!) {
createTask(title: $title, completed: $completed) {
id
title
completed
}
}
`;
export default function Home() {
const { loading, error, data } = useQuery(GET_TASKS);
const [createTask] = useMutation(CREATE_TASK);
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;
const handleCreateTask = async () => {
await createTask({
variables: { title: 'New Task', completed: false },
});
};
return (
<div>
<button onClick={handleCreateTask}>Add Task</button>
{data.tasks.map((task) => (
<div key={task.id}>
<h2>{task.title}</h2>
<p>{task.completed ? 'Completed' : 'Pending'}</p>
</div>
))}
</div>
);
}
Erreurs Frequentes et Debugging
1. Erreur : SyntaxError: Unexpected token
Message d'Erreur Exact :
SyntaxError: Unexpected token
Code qui la Cause :
const task = { id: '1', title: 'Task 1', completed: false };
// ...
return newTask;
Code Correct :
const task = { id: '1', title: 'Task 1', completed: false };
// ...
return task;
2. Erreur : Network Error
Message d'Erreur Exact :
Network Error
Code qui la Cause :
const client = new ApolloClient({
uri: 'http://localhost:4000/graphql',
cache: new InMemoryCache(),
});
Code Correct :
const client = new ApolloClient({
uri: 'http://localhost:4000/graphql',
cache: new InMemoryCache(),
headers: {
authorization: `Bearer ${localStorage.getItem('token')}`,
},
});
3. Erreur : Cannot read property 'map' of undefined
Message d'Erreur Exact :
Cannot read property 'map' of undefined
Code qui la Cause :
const { loading, error, data } = useQuery(GET_TASKS);
// ...
return (
<div>
{data.tasks.map((task) => (
<div key={task.id}>
<h2>{task.title}</h2>
<p>{task.completed ? 'Completed' : 'Pending'}</p>
</div>
))}
</div>
);
Code Correct :
const { loading, error, data } = useQuery(GET_TASKS);
// ...
if (loading) return <p>Loading...</p>;
if (error) return <p>Error :(</p>;
return (
<div>
{data.tasks.map((task) => (
<div key={task.id}>
<h2>{task.title}</h2>
<p>{task.completed ? 'Completed' : 'Pending'}</p>
</div>
))}
</div>
);
Pour Aller Plus Loin
1. Authentification avec JWT et Apollo Link Context
- Concept Avancé : Utilisez Apollo Link Context pour ajouter un token d'authentification à chaque requête.
- Lien Vers le Concept Avancé : Apollo Client Authentication
2. Optimisation des Requêtes avec GraphQL
- Concept Avancé : Utilisez directives de fragment pour éviter la sur-récupération et le bloat.
- Lien Vers le Concept Avancé : GraphQL Fragments
3. Intégration avec Prisma et TypeORM
- Concept Avancé : Utilisez Prisma ou TypeORM pour gérer les données dans votre base de données.
- Lien Vers le Concept Avancé : Prisma / TypeORM
Défi Pratique
Défi : Créez un mini-projet complet en utilisant Next.js, Apollo Client et GraphQL pour créer une application de gestion de notes. Les utilisateurs devraient pouvoir ajouter, modifier et supprimer des notes.
Instructions :
- Créez un serveur GraphQL avec des opérations CRUD (Create, Read, Update, Delete) pour les notes.
- Créez une application Next.js qui utilise Apollo Client pour consommer l'API GraphQL.
- Ajoutez des composants React pour afficher et modifier les notes.
Indice :
Utilisez localStorage pour stocker temporairement le token d'authentification pendant ce défi.