No desenvolvimento web, otimizar e dimensionar aplicações sempre foi um problema. O React.js teve um sucesso extraordinário no desenvolvimento de front-end como uma ferramenta, fornecendo uma maneira robusta de criar interfaces de usuário. Mas isso se torna complicado com o crescimento das aplicações, especialmente quando se trata de vários endpoints de API REST. Preocupações como over-fetching, onde dados excessivos são necessários, podem ser uma fonte de gargalos de desempenho e uma experiência de usuário ruim.
Entre as soluções para esses desafios está a adoção do uso de GraphQL com aplicações React. Se seu backend tem vários endpoints de API REST, então introduzir uma camada GraphQL que chama internamente seus endpoints de API REST pode melhorar sua aplicação em relação ao overfetching e otimizar sua aplicação de front-end. Neste artigo, você encontrará como usar, as vantagens e desvantagens desta abordagem, vários desafios e como lidar com eles. Também iremos mergulhar mais fundo em alguns exemplos práticos de como o GraphQL pode ajudá-lo a melhorar a forma como você trabalha com seus dados.
Overfetching em APIs REST
Nas APIs REST, o overfetching ocorre quando a quantidade de dados que a API entrega para o cliente é maior do que o necessário. Este é um problema comum em APIs REST, que frequentemente retornam um Schema de Objeto ou Resposta fixo. Para entender melhor esse problema, vamos considerar um exemplo.
Considere uma página de perfil de usuário onde é necessário mostrar apenas o nome
e email
do usuário. Com uma API REST típica, buscar os dados do usuário pode parecer assim:
fetch('/api/users/1')
.then(response => response.json())
.then(user => {
// Use the user's name and profilePicture in the UI
});
A resposta da API incluirá dados desnecessários:
{
"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
}
Embora o aplicativo exija apenas os campos de nome e e-mail do usuário, a API retorna todo o objeto do usuário. Esses dados adicionais frequentemente aumentam o tamanho da carga útil, consomem mais largura de banda e podem eventualmente desacelerar o aplicativo quando usado em um dispositivo com recursos limitados ou uma conexão de rede lenta.
GraphQL como Solução
O GraphQL aborda o problema do overfetching permitindo que os clientes solicitem exatamente os dados de que precisam. Ao integrar um servidor GraphQL em seu aplicativo, você pode criar uma camada de recuperação de dados flexível e eficiente que se comunica com suas APIs REST existentes.
Como Funciona
1. Configuração do Servidor GraphQL
Você introduz um servidor GraphQL que atua como um intermediário entre seu frontend React e as APIs REST.
2. Definição do Esquema
Você define um esquema GraphQL que especifica os tipos de dados e consultas que seu frontend requer.
3. Implementação de Resolvers
Você implementa resolvers no servidor GraphQL que buscam dados das APIs REST e retornam apenas os campos necessários.
4. Integração do Front-End
Você atualiza seu aplicativo React para usar consultas GraphQL em vez de chamadas diretas à API REST.
Essa abordagem permite que você otimize a recuperação de dados sem reformular sua infraestrutura de backend existente.
Implementando GraphQL em um Aplicativo React
Vamos ver como configurar um servidor GraphQL e integrá-lo a um aplicativo React.
Instalar Dependências
npm install apollo-server graphql axios
Definir o Esquema
Criar um arquivo chamado 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;
Este esquema define um tipo User
e uma consulta user
que busca um usuário por ID.
Implementar os Resolvedores
Criar um arquivo chamado 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;
O resolvedor para a consulta user
busca dados da API REST e retorna apenas os campos necessários.
Vamos usar https://jsonplaceholder.typicode.com/ para nossa API REST falsa.
Configurar o Servidor
Criar um arquivo 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}`);
});
Iniciar o servidor:
node server.js
Seu servidor GraphQL está ativo em http://localhost:4000/graphql, e se você consultar seu servidor, ele o levará para esta página.
Integrando com o Aplicativo React
Agora vamos alterar o aplicativo React para usar a API GraphQL.
Instalar o Cliente Apollo
npm install @apollo/client graphql
Configurar o Cliente Apollo
import { ApolloClient, InMemoryCache } from '@apollo/client';
const client = new ApolloClient({
uri: 'http://localhost:4000',
cache: new InMemoryCache(),
});
Escrever a Consulta GraphQL
const GET_USER = gql`
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
`;
Agora, integre os trechos de código acima com seu aplicativo React. Aqui está um aplicativo react simples abaixo, que permite a um usuário selecionar o ID do usuário e exibir as informações:
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;
Resultado
Você verá detalhes simples do usuário assim: [Link do Github].
Trabalhando Com Múltiplos Endpoints
Imagine um cenário onde você precisa recuperar as postagens de um usuário específico, junto com os comentários individuais em cada postagem. Em vez de fazer três chamadas de API separadas do seu aplicativo React no frontend e lidar com dados desnecessários, você pode simplificar o processo com GraphQL. Ao definir um esquema e criar uma consulta GraphQL, você pode solicitar apenas os dados exatos que sua interface de usuário requer, o que é um pedido eficiente tudo em um.
Precisamos buscar dados do usuário, suas postagens e comentários para cada postagem a partir dos diferentes endpoints. Usaremos fetch para reunir dados dos múltiplos endpoints e retorná-los via GraphQL.
Atualizar Resolvers
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;
Atualizar Esquema 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;
A configuração do servidor em server.js
permanece a mesma. Assim que atualizarmos o código do React.js, obteremos a saída abaixo:
Resultado
Você verá um usuário detalhado assim: [Link do Github].
Benefícios Dessa Abordagem
Integrar o GraphQL ao seu aplicativo React oferece várias vantagens:
Eliminando Overfetching
Um recurso chave do GraphQL é que ele busca exatamente o que você solicita. O servidor retorna apenas os campos solicitados e garante que a quantidade de dados transferidos pela rede seja reduzida, servindo apenas o que a consulta demanda, melhorando assim o desempenho.
Simplificando o Código do Front-End
O GraphQL permite que você obtenha as informações necessárias em uma única consulta, independentemente de sua origem. Internamente, ele pode estar fazendo 3 chamadas de API para obter as informações. Isso ajuda a simplificar seu código frontend, pois agora você não precisa orquestrar diferentes solicitações assíncronas e combinar seus resultados.
Melhorando a Experiência do Desenvolvedor
Uma tipagem forte e a introspecção de esquemas oferecem melhores ferramentas e verificação de erros do que na implementação tradicional de APIs. Além disso, existem ambientes interativos onde os desenvolvedores podem construir e testar consultas, incluindo GraphiQL ou Apollo Explorer.
Abordando Complexidades e Desafios
Essa abordagem tem algumas vantagens, mas também introduz alguns desafios que devem ser gerenciados.
Camada Adicional de Backend
A introdução do servidor GraphQL cria uma camada extra em sua arquitetura de backend, e se não for gerenciada adequadamente, torna-se um ponto único de falha.
Solução
Preste atenção ao manuseio de erros e monitoramento. Ferramentas de containerização e orquestração, como Docker e Kubernetes, podem ajudar a gerenciar escalabilidade e confiabilidade.
Potencial Sobrecarga de Desempenho
O servidor GraphQL pode fazer múltiplas chamadas de API REST para resolver uma única consulta, o que pode introduzir latência e sobrecarga ao sistema.
Solução
Armazene em cache os resultados para evitar fazer várias chamadas à API. Algumas ferramentas, como DataLoader, podem gerenciar o processo de agrupamento e cache de solicitações.
Conclusão
“A simplicidade é a derradeira sofisticação” — Leonardo da Vinci
Integrar o GraphQL em sua aplicação React vai além de uma otimização de desempenho — é uma jogada estratégica em direção à construção de aplicações mais manuteníveis, escaláveis e eficientes. Ao lidar com o excesso de dados e simplificar o gerenciamento de informações, você não apenas melhora a experiência do usuário, como também capacita sua equipe de desenvolvimento com melhores ferramentas e práticas.
Embora a introdução de uma camada GraphQL traga seus próprios desafios, os benefícios frequentemente superam as complexidades. Ao planejar cuidadosamente sua implementação, otimizar seus resolvers e proteger seus endpoints, você pode mitigar possíveis desvantagens. Além disso, a flexibilidade que o GraphQL oferece pode tornar sua aplicação à prova de futuro à medida que cresce e evolui.
Adotar o GraphQL não significa abandonar suas atuais APIs REST. Pelo contrário, permite que você aproveite suas vantagens ao mesmo tempo que fornece uma camada de acesso a dados mais eficiente e flexível para suas aplicações front-end. Essa abordagem híbrida combina a confiabilidade do REST com a agilidade do GraphQL, proporcionando o melhor dos dois mundos.
Se você está pronto para levar sua aplicação React para o próximo nível, considere integrar o GraphQL em sua estratégia de busca de dados. A jornada pode apresentar desafios, mas as recompensas — um processo de desenvolvimento mais tranquilo, desenvolvedores mais felizes e usuários satisfeitos — tornam-na um esforço que vale a pena.
Código Completo Disponível
Você pode encontrar o código completo para esta implementação no meu repositório do GitHub.
Source:
https://dzone.com/articles/enhancing-react-applications-with-graphql-over-rest-apis