Inicio / Trilha 3 / Modulo 3.2
MODULO 3.2

πŸ”— APIs e Data Layer

REST, GraphQL, data fetching patterns, gerenciamento de estado server-side e estrategias de cache no frontend.

πŸ“š
6
Topicos
⏱️
70min
Duracao
πŸ“Š
Avancado
Nivel
🎯
Full Stack
Tipo
1

🌐 REST vs GraphQL

Escolhendo a arquitetura certa

REST usa endpoints fixos que retornam estruturas predefinidas. GraphQL oferece um unico endpoint com queries flexiveis. A escolha impacta desenvolvimento, performance e manutencao.

Para dashboards, a decisao depende da complexidade. Dashboards simples com dados fixos = REST. Dashboards com muitas views diferentes = GraphQL.

βš–οΈ Comparacao REST vs GraphQL

Aspecto REST GraphQL
Overfetching Comum - recebe tudo Nunca - pede so o que precisa
Underfetching Precisa de multiplas requests Uma query resolve
Caching HTTP cache nativo Requer Apollo/URQL
Complexidade Simples de implementar Schema, resolvers, types
Ideal para APIs publicas, CRUD simples Apps complexos, mobile

πŸ’» Codigo: REST vs GraphQL

// REST - Multiplas requests
// 3 requests para montar dashboard
const user = await fetch('/api/users/1');
const orders = await fetch('/api/users/1/orders');
const stats = await fetch('/api/users/1/stats');

// Overfetching: recebe 50 campos
// mas precisa de apenas 5
// GraphQL - Uma query
const { data } = await client.query({
  query: gql`
    query Dashboard($userId: ID!) {
      user(id: $userId) {
        name
        orders(limit: 5) { total }
        stats { revenue, count }
      }
    }
  `,
  variables: { userId: 1 }
});

πŸ’‘ Dica Pratica

Para dashboards Next.js: Use REST com Route Handlers para casos simples. Para dashboards complexos com muitos componentes buscando dados diferentes, GraphQL com Apollo Client oferece melhor DX e cache automatico.

2

πŸ”„ TanStack Query / SWR

Server state management

TanStack Query (ex React Query) e SWR sao bibliotecas para gerenciar dados que vem do servidor. Elas abstraem fetching, caching, revalidacao, retries e sincronizacao.

Antes delas, cada projeto reinventava a roda com useEffect + useState. Agora loading, error, data, refetch, cache sao tratados automaticamente.

🎯 Recursos Principais

Auto Caching

Dados ficam em cache e sao reutilizados entre componentes.

Background Refetch

Atualiza dados em background quando usuario volta a aba.

Stale Time

Define quanto tempo dados sao considerados frescos.

Retry Logic

Retenta automaticamente em caso de falha de rede.

πŸ’» Codigo: TanStack Query em Dashboard

import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';

// Hook para buscar metricas
function useMetrics(dateRange: string) {
  return useQuery({
    queryKey: ['metrics', dateRange],
    queryFn: () => fetch(`/api/metrics?range=${dateRange}`).then(r => r.json()),
    staleTime: 1000 * 60 * 5, // 5 minutos antes de refetch
    refetchOnWindowFocus: true, // Atualiza ao voltar a aba
  });
}

// Componente usando o hook
function MetricsCard() {
  const { data, isLoading, error, refetch } = useMetrics('30d');

  if (isLoading) return ;
  if (error) return ;

  return (
    

Receita: {data.revenue}

Clientes: {data.customers}

); } // Mutation para atualizar dados function useUpdateMetric() { const queryClient = useQueryClient(); return useMutation({ mutationFn: (data) => fetch('/api/metrics', { method: 'POST', body: JSON.stringify(data) }), onSuccess: () => { // Invalida cache para refetch queryClient.invalidateQueries({ queryKey: ['metrics'] }); } }); }

βœ… Fazer vs ❌ Evitar

βœ… Fazer
  • β€’ Query keys consistentes e hierarquicas
  • β€’ staleTime apropriado ao tipo de dado
  • β€’ Invalidar queries apos mutations
  • β€’ Prefetch em hover para UX rapida
❌ Evitar
  • β€’ useQuery dentro de loops
  • β€’ Query keys dinamicas sem memoize
  • β€’ Ignorar estados de loading/error
  • β€’ refetchOnMount em dados estaticos
3

⚠️ Error Handling e Retry

Resiliencia de APIs

Error handling robusto e essencial para dashboards enterprise. Falhas de rede, timeouts e erros de API vao acontecer - a questao e como seu app reage.

Um dashboard que mostra tela branca quando a API falha e inutil. Usuarios precisam ver dados stale, fallbacks ou pelo menos mensagens claras.

πŸ”„ Estrategias de Retry

Exponential Backoff

Aumenta o intervalo entre retries exponencialmente.

1s β†’ 2s β†’ 4s β†’ 8s β†’ desiste
Circuit Breaker

Para de tentar temporariamente apos muitas falhas.

5 falhas β†’ circuito aberto por 30s β†’ tenta novamente
Fallback Data

Mostra dados em cache ou defaults quando falha.

API falhou β†’ mostra dados de 5min atras

πŸ’» Codigo: Error Handling Completo

// Hook com retry e fallback
function useMetricsWithFallback() {
  return useQuery({
    queryKey: ['metrics'],
    queryFn: async () => {
      const res = await fetch('/api/metrics');
      if (!res.ok) {
        throw new Error(`HTTP ${res.status}`);
      }
      return res.json();
    },
    retry: 3,
    retryDelay: (attempt) => Math.min(1000 * 2 ** attempt, 30000),
    // Fallback: mantem dados antigos em erro
    placeholderData: (previousData) => previousData,
    // Ou dados estaticos
    initialData: { revenue: 0, customers: 0 },
  });
}

// Error Boundary para erros de render
function DashboardErrorBoundary({ children }) {
  return (
     (
        

Erro ao carregar dashboard

{error.message}

)} > {children}
); }
4

⏳ Loading States e Skeletons

Feedback visual durante carregamento

Skeleton screens mostram a estrutura da UI enquanto dados carregam. Diferente de spinners, skeletons mantem o layout estavel e reduzem a percepcao de espera.

Estudos mostram que usuarios percebem skeletons como 30% mais rapidos que spinners para o mesmo tempo de carga. E a diferenca entre "lento" e "fluido".

πŸ‘οΈ Exemplo Visual de Skeleton

Carregando...
Carregado!
Receita
R$ 1.234.567
β–² 12.5%

πŸ’» Codigo: Skeleton Component

// Skeleton base reutilizavel
function Skeleton({ className }: { className?: string }) {
  return (
    
); } // Skeleton para card de metricas function MetricCardSkeleton() { return (
); } // Uso com React Suspense function Dashboard() { return ( }> ); } // Ou com TanStack Query function MetricCard() { const { data, isLoading } = useMetrics(); if (isLoading) return ; return (

{data.label}

{data.value}

); }
5

πŸ“Š Data Normalization

Estrutura de dados eficiente

Data normalization e organizar dados aninhados vindos da API em estruturas planas com referencias por ID. Isso evita duplicacao e facilita atualizacoes parciais.

Quando o mesmo usuario aparece em 10 lugares, atualizar o nome dele em um lugar deve refletir em todos. Sem normalizacao, voce precisa atualizar 10 lugares manualmente.

πŸ” Antes vs Depois de Normalizar

❌ Nao Normalizado
{
  orders: [
    {
      id: 1,
      user: { id: 10, name: 'Ana' },
      items: [...]
    },
    {
      id: 2,
      user: { id: 10, name: 'Ana' }, // duplicado!
      items: [...]
    }
  ]
}
βœ… Normalizado
{
  users: {
    10: { id: 10, name: 'Ana' }
  },
  orders: {
    1: { id: 1, userId: 10, itemIds: [1,2] },
    2: { id: 2, userId: 10, itemIds: [3] }
  },
  orderIds: [1, 2]
}

πŸ’» Codigo: Normalizando com normalizr

import { normalize, schema } from 'normalizr';

// Definir schemas
const userSchema = new schema.Entity('users');
const orderSchema = new schema.Entity('orders', {
  user: userSchema
});

// Dados da API
const apiResponse = {
  orders: [
    { id: 1, user: { id: 10, name: 'Ana' }, total: 100 },
    { id: 2, user: { id: 10, name: 'Ana' }, total: 200 }
  ]
};

// Normalizar
const normalized = normalize(apiResponse, {
  orders: [orderSchema]
});

// Resultado:
// {
//   entities: {
//     users: { 10: { id: 10, name: 'Ana' } },
//     orders: {
//       1: { id: 1, userId: 10, total: 100 },
//       2: { id: 2, userId: 10, total: 200 }
//     }
//   },
//   result: { orders: [1, 2] }
// }
6

πŸ”” Real-time e WebSockets

Dados em tempo real

WebSockets permitem comunicacao bidirecional entre cliente e servidor. Diferente de HTTP que e request-response, WebSockets mantΓ©m uma conexao aberta para push de dados.

Para dashboards de monitoramento, dados precisam atualizar em segundos, nao minutos. WebSockets ou Server-Sent Events (SSE) sao essenciais para isso.

βš–οΈ Polling vs WebSocket vs SSE

Polling Simples

Cliente pergunta "tem novidade?" a cada X segundos. Simples mas ineficiente.

WebSocket Bidirecional

Conexao persistente. Cliente e servidor enviam mensagens a qualquer momento.

SSE (Server-Sent Events) Unidirecional

Servidor envia eventos para cliente. Mais simples que WebSocket, HTTP nativo.

πŸ’» Codigo: Real-time com Socket.io

// Cliente React
import { useEffect, useState } from 'react';
import { io } from 'socket.io-client';

function useRealtimeMetrics() {
  const [metrics, setMetrics] = useState(null);
  const [connected, setConnected] = useState(false);

  useEffect(() => {
    const socket = io('wss://api.example.com', {
      auth: { token: getToken() }
    });

    socket.on('connect', () => setConnected(true));
    socket.on('disconnect', () => setConnected(false));

    // Escuta eventos de metricas
    socket.on('metrics:update', (data) => {
      setMetrics(data);
    });

    // Subscribe a sala especifica
    socket.emit('subscribe', { room: 'dashboard-metrics' });

    return () => socket.disconnect();
  }, []);

  return { metrics, connected };
}

// Uso no componente
function LiveDashboard() {
  const { metrics, connected } = useRealtimeMetrics();

  return (
    
{connected ? '● Ao vivo' : 'β—‹ Desconectado'}
{metrics && }
); }

πŸ’‘ Dica Pratica

Para Next.js com Vercel: Use Pusher, Ably ou Supabase Realtime. Vercel serverless nao suporta WebSockets persistentes nativamente. SSE funciona mas com limitacoes. Servicos gerenciados sao a melhor opcao.

πŸ“ Resumo do Modulo

βœ“
REST vs GraphQL - REST para simples, GraphQL para complexo
βœ“
TanStack Query - Server state com cache, retry, revalidacao automatica
βœ“
Error Handling - Exponential backoff, circuit breaker, fallback data
βœ“
Skeletons - Feedback visual que reduz percepcao de espera
βœ“
Normalization - Dados planos com referencias, sem duplicacao
βœ“
Real-time - WebSocket/SSE para dados ao vivo