🚀 Dominando o Consumo de APIs com Axios no Next.js

Uma aula detalhada sobre Client-Side, Server-Side e Melhores Práticas.

📋 Agenda da Aula

  1. Configuração: Instalando o Axios.
  2. CSR (Client-Side Rendering): O padrão React com useEffect.
  3. SSR (Server-Side Rendering): Buscando dados a cada request com getServerSideProps.
  4. SSG (Static Site Generation): Buscando dados no build com getStaticProps.
  5. Melhores Práticas (1): Criando uma instância do Axios.
  6. Melhores Práticas (2): Usando API Routes para proteger chaves (BFF).
  7. Resumo Comparativo: Quando usar cada método.

⚙️ Configuração Inicial

Antes de começar, você precisa de:

  • Conhecimento básico de React (Hooks) e Next.js.
  • Um projeto Next.js iniciado (npx create-next-app).

Instalando o Axios:
Abra seu terminal e rode o comando:

npm install axios
# ou
yarn add axios

1. Client-Side Rendering (CSR)

Este é o método padrão do React. A página é carregada e, no navegador, o JavaScript busca os dados.

  • Quando usar: Dados específicos do usuário (dashboards), dados que mudam com frequência, dados não essenciais para a primeira carga.
  • Prós: Rápida carga inicial da página (UI).
  • Contras: O usuário vê um "loading". Ruim para SEO, pois os dados não estão no HTML inicial.

CSR: Exemplo com useEffect

Os dados são buscados no cliente usando useEffect e useState.

pages/produtos-csr.js

import { useState, useEffect } from 'react';
import axios from 'axios';

export default function ProdutosCSR() {
  const [produtos, setProdutos] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchProdutos = async () => {
      try {
        setLoading(true);
        const res = await axios.get('[https://dummyjson.com/products?limit=10](https://dummyjson.com/products?limit=10)');
        setProdutos(res.data.products);
      } catch (err) {
        console.error(err);
      } finally {
        setLoading(false);
      }
    };
    fetchProdutos();
  }, []); // Array vazio: roda 1x no cliente
  if (loading) return <p>Carregando...</p>;

  return (
    <div>
      <h1>Nossos Produtos (CSR)</h1>
      <ul>
        {produtos.map((p) => <li key={p.id}>{p.title}</li>)}
      </ul>
    </div>
  );
}

2. Server-Side Rendering (SSR)

O Next.js executa a busca de dados no servidor a cada nova requisição. A página é enviada ao cliente já completa.

  • Função: getServerSideProps
  • Quando usar: Dados que mudam a todo instante e precisam de SEO (ex: páginas de busca, cotação de moedas, perfis de usuário).
  • Prós: Ótimo para SEO. Dados sempre 100% atualizados.
  • Contras: Mais lento que SSG, pois o servidor sempre espera a API responder.

SSR: Exemplo com getServerSideProps

Dividimos o arquivo em duas partes: o componente e a função de data fetching.

pages/produtos-ssr.js

import axios from 'axios';

// 1. O Componente (recebe 'props' do servidor)
export default function ProdutosSSR({ produtos }) {
  return (
    <div>
      <h1>Nossos Produtos (SSR)</h1>
      <ul>
        {produtos.map((p) => <li key={p.id}>{p.title}</li>)}
      </ul>
    </div>
  );
}

// 2. A Função (Roda NO SERVIDOR a cada request)
export async function getServerSideProps() {
  try {
    const response = await axios.get('[https://dummyjson.com/products?limit=10](https://dummyjson.com/products?limit=10)');
    
    return {
      props: { // Os dados são injetados em 'props'
        produtos: response.data.products,
      },
    };
  } catch (err) {
    return { props: { produtos: [] } };
  }
}

3. Static Site Generation (SSG)

O Next.js executa a busca no servidor apenas uma vez, em tempo de build. Ele gera um HTML estático.

  • Função: getStaticProps
  • Quando usar: Dados que mudam raramente (posts de blog, páginas de marketing, documentação).
  • Prós: Performance imbatível (servido de CDN). Ótimo para SEO.
  • Contras: Dados ficam "congelados" até o próximo build. (Pode ser resolvido com ISR).

ISR (Incremental Static Regeneration): Use revalidate: 60 em getStaticProps para regerar a página a cada 60 segundos.

SSG: Exemplo com getStaticProps

A estrutura é quase idêntica ao SSR, mas a função tem um nome diferente.

pages/produtos-ssg.js

import axios from 'axios';

// 1. O Componente (igual ao SSR)
export default function ProdutosSSG({ produtos }) {
  return (
    <div>
      <h1>Nossos Produtos (SSG)</h1>
      <ul>
        {produtos.map((p) => <li key={p.id}>{p.title}</li>)}
      </ul>
    </div>
  );
}

// 2. A Função (Roda NO SERVIDOR apenas 1x no build)
export async function getStaticProps() {
  try {
    const response = await axios.get('[https://dummyjson.com/products?limit=10](https://dummyjson.com/products?limit=10)');
    
    return {
      props: {
        produtos: response.data.products,
      },
      // revalidate: 60, // Opcional: Ativa o ISR
    };
  } catch (err) {
    return { props: { produtos: [] } };
  }
}

4. 🏆 Melhor Prática 1: Instância do Axios

Não repita sua baseURL e headers em todo lugar. Crie um serviço centralizado.

1. Crie lib/api.js

import axios from 'axios';

const api = axios.create({
  baseURL: '[https://dummyjson.com](https://dummyjson.com)',
  // headers: { 'Authorization': 'Bearer SEU_TOKEN_AQUI' }
});

export default api;

2. Use a instância nas suas páginas

// Em getServerSideProps ou getStaticProps
import api from '../lib/api'; // Nossa instância!

export async function getServerSideProps() {
  // Usamos 'api' e apenas o path relativo
  const response = await api.get('/products?limit=10');
  
  return {
    props: { produtos: response.data.products }
  };
}

5. 🏆 Melhor Prática 2: API Routes (BFF)

Problema: E se a API precisa de uma chave secreta (API Key)?
Você NUNCA deve expor chaves secretas no Client-Side (CSR).

Solução: Use as API Routes do Next.js como um Backend-for-Frontend (BFF).

Fluxo:
Seu Cliente (CSR) → Sua API Route (/api/...) → API Externa (com Axios)

O Axios roda no seu servidor, protegendo a chave.

API Routes: Exemplo (BFF)

1. Crie a API Route (Servidor)
pages/api/produtos.js

// Este código SÓ roda no servidor
import axios from 'axios';

export default async function handler(req, res) {
  if (req.method !== 'GET') {
    return res.status(405).end();
  }
  
  try {
    const response = await axios.get('[https://dummyjson.com/products](https://dummyjson.com/products)', {
      params: req.query, // Repassa query params (ex: ?limit=5)
      // headers: { 'Authorization': `Bearer ${process.env.API_SECRET_KEY}` }
    });
    res.status(200).json(response.data);
  } catch (error) {
    res.status(500).json({ message: 'Erro ao buscar dados' });
  }
}

API Routes: Exemplo (BFF)

2. Consuma sua própria API (Cliente)
Agora, seu componente CSR chama a sua API interna, que é segura.

pages/produtos-csr.js (Modificado)

import { useState, useEffect } from 'react';
import axios from 'axios';

export default function ProdutosCSR() {
  const [produtos, setProdutos] = useState([]);

  useEffect(() => {
    const fetchProdutos = async () => {
      try {
        // ATENÇÃO: Chamando a NOSSA API interna!
        const res = await axios.get('/api/produtos?limit=10'); 
        setProdutos(res.data.products);
      } catch (err) {
        console.error(err);
      }
    };
    fetchProdutos();
  }, []);

  // ... render ...
}

📊 Resumo Comparativo

Método Função Next.js Onde o Axios Roda? Quando Roda? SEO Velocidade
CSR useEffect Navegador Após carregar a pág. Ruim Rápido (UI)
SSR getServerSideProps Servidor A cada requisição Ótimo Lento
SSG getStaticProps Servidor Em tempo de build Perfeito Instantâneo
API Route pages/api/* Servidor Sob demanda N/A N/A

✅ Conclusão

  • CSR (useEffect): Para dados do usuário, não-críticos.
  • SSR (getServerSideProps): Para dados dinâmicos e SEO.
  • SSG (getStaticProps): Para dados estáticos e SEO (a opção mais rápida).
  • API Routes: Para proteger suas chaves de API e criar um proxy (BFF).

Obrigado!