Dans le développement web, l’optimisation et la mise à l’échelle des applications ont toujours été un problème. React.js a connu un succès extraordinaire dans le développement front-end en tant qu’outil, offrant un moyen robuste de créer des interfaces utilisateur. Mais cela devient compliqué avec le développement des applications, surtout en ce qui concerne les multiples points de terminaison de l’API REST. Des préoccupations telles que la surcharge, où des données excessives sont nécessaires, peuvent être une source de goulot d’étranglement des performances et d’une mauvaise expérience utilisateur.
Parmi les solutions à ces défis figure l’adoption de l’utilisation de GraphQL avec les applications React. Si votre back-end comporte plusieurs points de terminaison REST, l’introduction d’une couche GraphQL qui appelle en interne vos points de terminaison d’API REST peut améliorer votre application en évitant la surcharge et en rationalisant votre application frontale. Dans cet article, vous découvrirez comment l’utiliser, les avantages et inconvénients de cette approche, divers défis, et comment les aborder. Nous plongerons également plus en profondeur dans quelques exemples pratiques de la manière dont GraphQL peut vous aider à améliorer la façon dont vous travaillez avec vos données.
Surcharge dans les API REST
Dans les API REST, la surcharge se produit lorsque la quantité de données que l’API fournit au client est supérieure à ce que le client nécessite. C’est un problème courant avec les API REST, qui renvoient souvent un schéma d’objet ou de réponse fixe. Pour mieux comprendre ce problème, considérons un exemple.
Imaginons une page de profil utilisateur où seuls le nom
et l’email
de l’utilisateur doivent être affichés. Avec une API REST typique, la récupération des données de l’utilisateur pourrait ressembler à ceci :
fetch('/api/users/1')
.then(response => response.json())
.then(user => {
// Use the user's name and profilePicture in the UI
});
La réponse de l’API inclura des données inutiles:
{
"id": 1,
"name": "John Doe",
"profilePicture": "/images/john.jpg",
"email": "[email protected]",
"address": "123 Denver St",
"phone": "111-555-1234",
"preferences": {
"newsletter": true,
"notifications": true
},
// ...more details
}
Bien que l’application n’exige que les champs nom et e-mail de l’utilisateur, l’API renvoie l’ensemble de l’objet utilisateur. Ces données supplémentaires augmentent souvent la taille de la charge utile, consomment plus de bande passante et peuvent éventuellement ralentir l’application lorsqu’elle est utilisée sur un appareil avec des ressources limitées ou une connexion réseau lente.
GraphQL comme solution
GraphQL aborde le problème de la surconsommation de données en permettant aux clients de demander exactement les données dont ils ont besoin. En intégrant un serveur GraphQL dans votre application, vous pouvez créer une couche de récupération de données flexible et efficace qui communique avec vos API REST existantes.
Comment cela fonctionne
1. Configuration du serveur GraphQL
Vous introduisez un serveur GraphQL qui sert d’intermédiaire entre votre frontend React et les API REST.
2. Définition du schéma
Vous définissez un schéma GraphQL qui spécifie les types de données et les requêtes dont votre frontend a besoin.
3. Implémentation des résolveurs
Vous implémentez des résolveurs dans le serveur GraphQL qui récupèrent les données des API REST et renvoient uniquement les champs nécessaires.
4. Intégration Front-End
Vous mettez à jour votre application React pour utiliser des requêtes GraphQL au lieu d’appels directs aux API REST.
Cette approche vous permet d’optimiser la récupération de données sans réorganiser votre infrastructure backend existante.
Implémentation de GraphQL dans une application React
Regardons comment configurer un serveur GraphQL et l’intégrer dans une application React.
Installer les dépendances
npm install apollo-server graphql axios
Définir le schéma
Créez un fichier appelé schema.js
:
const { gql } = require('apollo-server');
const typeDefs = gql`
type User {
id: ID!
name: String
email: String // Ensure this matches exactly with the frontend query
}
type Query {
user(id: ID!): User
}
`;
module.exports = typeDefs;
Ce schéma définit un type User
et une requête user
qui récupère un utilisateur par ID.
Implémenter les resolveurs
Créez un fichier appelé resolvers.js
:
const resolvers = {
Query: {
user: async (_, { id }) => {
try {
const response = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
const user = await response.json();
return {
id: user.id,
name: user.name,
email: user.email, // Return email instead of profilePicture
};
} catch (error) {
throw new Error(`Failed to fetch user: ${error.message}`);
}
},
},
};
module.exports = resolvers;
Le résolveur pour la requête user
récupère des données depuis l’API REST et renvoie uniquement les champs requis.
Nous utiliserons https://jsonplaceholder.typicode.com/ pour notre fausse API REST.
Configurer le serveur
Créez un fichier server.js
:
const { ApolloServer } = require('apollo-server');
const typeDefs = require('./schema');
const resolvers = require('./resolvers');
const server = new ApolloServer({
typeDefs,
resolvers,
});
server.listen({ port: 4000 }).then(({ url }) => {
console.log(`GraphQL Server ready at ${url}`);
});
Démarrer le serveur:
node server.js
Votre serveur GraphQL est en ligne à l’adresse http://localhost:4000/graphql, et si vous interrogez votre serveur, il vous dirigera vers cette page.
Intégration dans l’application React
Nous allons maintenant modifier l’application React pour utiliser l’API GraphQL.
Installer Apollo Client
npm install @apollo/client graphql
Configurer Apollo Client
import { ApolloClient, InMemoryCache } from '@apollo/client';
const client = new ApolloClient({
uri: 'http://localhost:4000',
cache: new InMemoryCache(),
});
Écrire la requête GraphQL
const GET_USER = gql`
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
`;
Maintenant, intégrez les morceaux de code ci-dessus dans votre application React. Voici un exemple d’application React simple ci-dessous, qui permet à un utilisateur de sélectionner l’ID de l’utilisateur et d’afficher les informations:
import { useState } from 'react';
import { ApolloClient, InMemoryCache, ApolloProvider, gql, useQuery } from '@apollo/client';
import './App.css'; // Link to the updated CSS
const client = new ApolloClient({
uri: 'http://localhost:4000', // Ensure this is the correct URL for your GraphQL server
cache: new InMemoryCache(),
});
const GET_USER = gql`
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
`;
const User = ({ userId }) => {
const { loading, error, data } = useQuery(GET_USER, {
variables: { id: userId },
});
if (loading) return <p>Loading</p>;
if (error) return <p>Error: {error.message}</p>;
return (
<div className="user-container">
<h2>{data.user.name}</h2>
<p>Email: {data.user.email}</p>
</div>
);
};
const App = () => {
const [selectedUserId, setSelectedUserId] = useState("1");
return (
<ApolloProvider client={client}>
<div className="app-container">
<h1 className="title">GraphQL User Lookup</h1>
<div className="dropdown-container">
<label htmlFor="userSelect">Select User ID:</label>
<select
id="userSelect"
value={selectedUserId}
onChange={(e) => setSelectedUserId(e.target.value)}
>
{Array.from({ length: 10 }, (_, index) => (
<option key={index + 1} value={index + 1}>
{index + 1}
</option>
))}
</select>
</div>
<User userId={selectedUserId} />
</div>
</ApolloProvider>
);
};
export default App;
Résultat
Vous verrez des détails simples sur l’utilisateur comme ceci : [Lien Github].
Travailler avec plusieurs points de terminaison
Imaginez un scénario où vous devez récupérer les publications d’un utilisateur spécifique, ainsi que les commentaires individuels sur chaque publication. Au lieu de faire trois appels API séparés depuis votre application React, et de traiter des données inutiles, vous pouvez rationaliser le processus avec GraphQL. En définissant un schéma et en élaborant une requête GraphQL, vous pouvez demander uniquement les données précises dont votre interface utilisateur a besoin, ce qui constitue une demande efficace en une seule fois.
Nous devons récupérer les données utilisateur, leurs publications et les commentaires pour chaque publication à partir des différents points de terminaison. Nous utiliserons fetch pour rassembler les données des multiples points de terminaison et les renvoyer via GraphQL.
Mettre à jour les résolveurs
const fetch = require('node-fetch');
const resolvers = {
Query: {
user: async (_, { id }) => {
try {
// fetch user
const userResponse = await fetch(`https://jsonplaceholder.typicode.com/users/${id}`);
const user = await userResponse.json();
// fetch posts for a user
const postsResponse = await fetch(`https://jsonplaceholder.typicode.com/posts?userId=${id}`);
const posts = await postsResponse.json();
// fetch comments for a post
const postsWithComments = await Promise.all(
posts.map(async (post) => {
const commentsResponse = await fetch(`https://jsonplaceholder.typicode.com/comments?postId=${post.id}`);
const comments = await commentsResponse.json();
return { post, comments };
})
);
return {
id: user.id,
name: user.name,
email: user.email,
posts: postsWithComments,
};
} catch (error) {
throw new Error(`Failed to fetch user data: ${error.message}`);
}
},
},
};
module.exports = resolvers;
Mettre à jour le schéma GraphQL
const { gql } = require('apollo-server');
const typeDefs = gql`
type Comment {
id: ID!
name: String
email: String
body: String
}
type Post {
id: ID!
title: String
body: String
comments: [Comment]
}
type User {
id: ID!
name: String
email: String
posts: [Post]
}
type Query {
user(id: ID!): User
}
`;
module.exports = typeDefs;
La configuration du serveur dans server.js
reste la même. Une fois que nous avons mis à jour le code React.js, nous obtenons le résultat ci-dessous :
Résultat
Vous verrez un utilisateur détaillé comme ceci : [Lien Github].
Avantages de cette approche
L’intégration de GraphQL dans votre application React offre plusieurs avantages :
Élimination de la surcharge de données
Une caractéristique clé de GraphQL est qu’il ne récupère exactement que ce que vous demandez. Le serveur ne renvoie que les champs demandés et veille à ce que la quantité de données transférées sur le réseau soit réduite en ne servant que ce que la requête exige, améliorant ainsi les performances.
Simplification du code front-end
GraphQL vous permet d’obtenir les informations nécessaires dans une seule requête, indépendamment de leur origine. En interne, il peut effectuer 3 appels API pour récupérer les informations. Cela permet de simplifier votre code frontend car vous n’avez plus besoin d’orchestrer différents appels asynchrones et de combiner leurs résultats.
Amélioration de l’expérience des développeurs
Un typage fort et une introspection du schéma offrent de meilleurs outils et une meilleure vérification des erreurs que dans l’implémentation API traditionnelle. De plus, il existe des environnements interactifs où les développeurs peuvent construire et tester des requêtes, comme GraphiQL ou Apollo Explorer.
Adresse des complexités et des défis
Cette approche présente des avantages mais introduit également des défis qui doivent être gérés.
Une couche backend supplémentaire
L’introduction du serveur GraphQL crée une couche supplémentaire dans votre architecture backend, et s’il n’est pas géré correctement, il devient un point de défaillance unique.
Solution
Prêtez attention à la gestion des erreurs et à la surveillance. Les outils de conteneurisation et d’orchestration comme Docker et Kubernetes peuvent aider à gérer la scalabilité et la fiabilité.
Surcoût potentiel en performance
Le serveur GraphQL peut effectuer de multiples appels API REST pour résoudre une seule requête, ce qui peut introduire de la latence et un surcoût dans le système.
Solution
Mettez en cache les résultats pour éviter de faire plusieurs appels à l’API. Certains outils, comme DataLoader, peuvent gérer le processus de regroupement et de mise en cache des requêtes.
Conclusion
« La simplicité est la sophistication ultime » — Léonard de Vinci
Intégrer GraphQL dans votre application React est plus qu’une simple optimisation des performances — c’est un mouvement stratégique vers la création d’applications plus maintenables, évolutives et efficaces. En abordant le sur-récupération et en simplifiant la gestion des données, vous améliorez non seulement l’expérience utilisateur, mais vous donnez également à votre équipe de développement de meilleurs outils et pratiques.
Bien que l’introduction d’une couche GraphQL présente son propre ensemble de défis, les avantages l’emportent souvent sur les complexités. En planifiant soigneusement votre mise en œuvre, en optimisant vos résolveurs et en sécurisant vos points de terminaison, vous pouvez atténuer les inconvénients potentiels. De plus, la flexibilité que GraphQL offre peut rendre votre application pérenne à mesure qu’elle grandit et évolue.
Adopter GraphQL ne signifie pas abandonner vos API REST existantes. Au contraire, cela vous permet de tirer parti de leurs forces tout en fournissant une couche d’accès aux données plus efficace et flexible pour vos applications front-end. Cette approche hybride combine la fiabilité de REST avec l’agilité de GraphQL, vous offrant le meilleur des deux mondes.
Si vous êtes prêt à porter votre application React à un niveau supérieur, envisagez d’intégrer GraphQL dans votre stratégie de récupération de données. Le parcours peut présenter des défis, mais les récompenses — un processus de développement plus fluide, des développeurs plus heureux et des utilisateurs satisfaits — en font une entreprise qui en vaut la peine.
Code complet disponible
Vous pouvez trouver le code complet de cette implémentation sur mon dépôt GitHub.
Source:
https://dzone.com/articles/enhancing-react-applications-with-graphql-over-rest-apis