Nello sviluppo web, l’ottimizzazione e la scalabilità delle applicazioni sono sempre state una questione importante. React.js ha avuto un successo straordinario nello sviluppo frontend come strumento, offrendo un modo robusto per creare interfacce utente. Tuttavia, diventa complicato con l’aumentare delle applicazioni, soprattutto quando si tratta di più endpoint API REST. Preoccupazioni come l’over-fetching, dove vengono richiesti dati eccessivi, possono essere una fonte di colli di bottiglia nelle prestazioni e di una cattiva esperienza utente.
Tra le soluzioni a queste sfide c’è l’adozione dell’uso di GraphQL con le applicazioni React. Se il tuo backend ha più endpoint REST, introdurre uno strato GraphQL che chiama internamente i tuoi endpoint API REST può migliorare la tua applicazione dall’over-fetching e semplificare la tua applicazione frontend. In questo articolo, troverai come utilizzarlo, i vantaggi e gli svantaggi di questo approccio, varie sfide e come affrontarle. Approfondiremo anche alcuni esempi pratici di come GraphQL può aiutarti a migliorare i modi in cui lavori con i tuoi dati.
Overfetching nelle API REST
Nelle API REST, l’overfetching si verifica quando la quantità di dati che l’API consegna al client è maggiore di quanto richiesto dal client. Questo è un problema comune con le API REST, che spesso restituiscono uno schema di oggetto o risposta fisso. Per comprendere meglio questo problema, consideriamo un esempio.
Considera una pagina del profilo utente in cui è necessario mostrare solo il nome
e l’email
dell’utente. Con una tipica API REST, il recupero dei dati dell’utente potrebbe apparire così:
fetch('/api/users/1')
.then(response => response.json())
.then(user => {
// Use the user's name and profilePicture in the UI
});
La risposta dell’API includerà dati non necessari:
{
"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
}
Anche se l’applicazione richiede solo i campi nome ed email dell’utente, l’API restituisce l’intero oggetto utente. Questi dati aggiuntivi aumentano spesso le dimensioni del payload, consumano più larghezza di banda e possono alla fine rallentare l’applicazione quando viene utilizzata su un dispositivo con risorse limitate o una connessione di rete lenta.
GraphQL come Soluzione
GraphQL affronta il problema dell’overfetching consentendo ai client di richiedere esattamente i dati di cui hanno bisogno. Integrando un server GraphQL nella tua applicazione, puoi creare uno strato di recupero dati flessibile ed efficiente che comunica con le tue attuali API REST.
Come Funziona
1. Configurazione del Server GraphQL
Introduci un server GraphQL che funge da intermediario tra il tuo frontend React e le API REST.
2. Definizione dello Schema
Definisci uno schema GraphQL che specifica i tipi di dati e le query di cui il tuo frontend ha bisogno.
3. Implementazione dei Risolutori
Implementi risolutori nel server GraphQL che recuperano i dati dalle API REST e restituiscono solo i campi necessari.
4. Integrazione Front-End
Aggiorna la tua applicazione React per utilizzare le query GraphQL invece di chiamate dirette alle API REST.
Questo approccio ti consente di ottimizzare il recupero dei dati senza rivoluzionare l’infrastruttura backend esistente.
Implementazione di GraphQL in un’applicazione React
Vediamo come impostare un server GraphQL e integrarlo in un applicazione React.
Installa Dipendenze
npm install apollo-server graphql axios
Definisci lo Schema
Crea un file chiamato 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;
Questo schema definisce un tipo User
e una query user
che recupera un utente tramite ID.
Implementa i Risolutori
Crea un file chiamato 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;
Il risolutore per la query user
recupera i dati dall’API REST e restituisce solo i campi richiesti.
Utilizzeremo https://jsonplaceholder.typicode.com/ per la nostra falsa API REST.
Imposta il Server
Crea un file 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}`);
});
Avvia il server:
node server.js
Il tuo server GraphQL è attivo su http://localhost:4000/graphql, e se interroghi il tuo server, ti porterà a questa pagina.
Integrazione con l’Applicazione React
Ora cambieremo l’applicazione React per utilizzare l’API GraphQL.
Installa Apollo Client
npm install @apollo/client graphql
Configura Apollo Client
import { ApolloClient, InMemoryCache } from '@apollo/client';
const client = new ApolloClient({
uri: 'http://localhost:4000',
cache: new InMemoryCache(),
});
Scrivi la Query GraphQL
const GET_USER = gql`
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
`;
Ora, integra i pezzi di codice sopra con la tua app React. Ecco una semplice app React qui sotto, che consente a un utente di selezionare l’userId e visualizzare le informazioni:
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;
Risultato
Vedrai dettagli semplici dell’utente come questo: [Link di Github].
Lavorare Con Più Endpoint
Immagina uno scenario in cui devi recuperare i post di un utente specifico, insieme ai singoli commenti su ciascun post. Invece di effettuare tre chiamate API separate dalla tua app frontend React e gestire dati non necessari, puoi ottimizzare il processo con GraphQL. Definendo uno schema e creando una query GraphQL, puoi richiedere solo i dati esatti di cui ha bisogno la tua interfaccia utente, effettuando una richiesta efficiente in un’unica soluzione.
Dobbiamo recuperare i dati dell’utente, i loro post e i commenti per ogni post dai diversi endpoint. Utilizzeremo fetch per raccogliere i dati dai vari endpoint e restituirli tramite GraphQL.
Aggiornare i Resolver
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;
Aggiornare lo Schema 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 configurazione del server in server.js
rimane la stessa. Una volta aggiornato il codice React.js, otteniamo l’output seguente:
Risultato
Vedrai un dettagliato utente come questo: [Link di Github].
Vantaggi di Questo Approccio
Integrare GraphQL nella tua applicazione React offre diversi vantaggi:
Eliminazione del sovraccarico
Una caratteristica chiave di GraphQL è che recupera esattamente ciò che richiedi. Il server restituisce solo i campi richiesti e garantisce che la quantità di dati trasferiti sulla rete sia ridotta servendo solo ciò che la query richiede, migliorando così le prestazioni.
Semplificazione del Codice Front-End
GraphQL ti consente di ottenere le informazioni necessarie in un’unica query, indipendentemente dalla loro origine. Internamente, potrebbe effettuare 3 chiamate API per ottenere le informazioni. Questo aiuta a semplificare il tuo codice frontend perché ora non devi orchestrare diverse richieste asincrone e combinare i loro risultati.
Migliorare l’Esperienza dello Sviluppatore
Una forte tipizzazione e l’introspezione dello schema offrono strumenti migliori e un controllo degli errori rispetto all’implementazione API tradizionale. Inoltre, ci sono ambienti interattivi in cui gli sviluppatori possono costruire e testare query, tra cui GraphiQL o Apollo Explorer.
Affrontare Complessità e Sfide
Questo approccio ha alcuni vantaggi ma introduce anche alcune sfide che devono essere gestite.
Ulteriore Strato di Backend
L’introduzione del server GraphQL crea uno strato extra nella tua architettura backend e, se non gestito correttamente, diventa un singolo punto di fallimento.
Soluzione
Fai attenzione alla gestione degli errori e al monitoraggio. Strumenti di containerizzazione e orchestrazione come Docker e Kubernetes possono aiutare a gestire scalabilità e affidabilità.
Potenziale Sovraccarico di Prestazioni
Il server GraphQL potrebbe effettuare più chiamate API REST per risolvere una singola query, il che può introdurre latenza e sovraccarico nel sistema.
Soluzione
Memorizza nella cache i risultati per evitare di effettuare più chiamate all’API. Alcuni strumenti, come DataLoader, possono gestire il processo di batching e memorizzazione nella cache delle richieste.
Conclusione
“La semplicità è la massima sofisticazione” — Leonardo da Vinci
Integrare GraphQL nella tua applicazione React è più di una semplice ottimizzazione delle prestazioni: è una mossa strategica verso la creazione di applicazioni più manutenibili, scalabili ed efficienti. Affrontando il problema del sovrarecupero e semplificando la gestione dei dati, non solo migliori l’esperienza dell’utente, ma potenzi anche il tuo team di sviluppo con strumenti e pratiche migliori.
Seppur l’introduzione di uno strato GraphQL comporti le proprie sfide, i benefici spesso superano le complessità. Pianificando attentamente la tua implementazione, ottimizzando i tuoi risolutori e assicurando i tuoi endpoint, puoi mitigare i potenziali svantaggi. Inoltre, la flessibilità che GraphQL offre può rendere la tua applicazione pronta per il futuro mentre cresce ed evolve.
Abbracciare GraphQL non significa abbandonare le tue esistenti API REST. Al contrario, ti consente di sfruttare i loro punti di forza mentre fornisci uno strato di accesso ai dati più efficiente e flessibile per le tue applicazioni front-end. Questo approccio ibrido combina l’affidabilità di REST con l’agilità di GraphQL, offrendoti il meglio di entrambi i mondi.
Se sei pronto a portare la tua applicazione React al livello successivo, considera di integrare GraphQL nella tua strategia di recupero dei dati. Il percorso potrebbe presentare delle sfide, ma i risultati — un processo di sviluppo più fluido, sviluppatori più felici e utenti soddisfatti — rendono l’impegno degno di nota.
Codice completo disponibile
Puoi trovare il codice completo per questa implementazione nel mio repository GitHub.
Source:
https://dzone.com/articles/enhancing-react-applications-with-graphql-over-rest-apis