Server Actions são funções assíncronas do Next.js executadas no servidor e chamadas diretamente de componentes React, eliminando a necessidade de Route Handlers ou endpoints de API manuais. Com elas, a chave de API fica protegida no servidor, o código fica mais conciso e a integração com a API de CPF da CPFHub.io se reduz a poucas linhas. Esta abordagem é ideal para validação de CPF em formulários de cadastro, checkout e onboarding digital.
Introdução
Server Actions são uma funcionalidade do Next.js que permite executar código no servidor diretamente a partir de componentes React, sem a necessidade de criar Route Handlers ou endpoints de API manualmente. Essa abordagem simplifica a integração com APIs externas como o CPFHub.io, mantendo a chave de API segura e reduzindo a quantidade de código necessário.
O que são Server Actions
Server Actions são funções assíncronas executadas no servidor que podem ser chamadas diretamente de componentes React. Elas são marcadas com a diretiva 'use server'.
// actions/cpf-actions.js
'use server';
export async function consultarCpf(cpf) {
const cpfLimpo = cpf.replace(/\D/g, '');
if (cpfLimpo.length !== 11) {
return { success: false, error: 'CPF deve conter 11 dígitos' };
}
const response = await fetch(
`${process.env.CPFHUB_BASE_URL}/cpf/${cpfLimpo}`,
{
headers: {
'x-api-key': process.env.CPFHUB_API_KEY,
},
}
);
if (!response.ok) {
return { success: false, error: 'CPF não encontrado' };
}
const dados = await response.json();
if (!dados.success) {
return { success: false, error: 'CPF não encontrado na base' };
}
return {
success: true,
data: {
cpf: dados.data.cpf,
nome: dados.data.name,
nomeUpper: dados.data.nameUpper,
genero: dados.data.gender,
dataNascimento: dados.data.birthDate,
dia: dados.data.day,
mes: dados.data.month,
ano: dados.data.year,
},
};
}
| Característica | Server Actions | Route Handlers |
|---|---|---|
| Arquivo separado | Não obrigatório | Sim (route.js) |
| Chamada do cliente | Direta (como função) | Via fetch |
| Segurança da API Key | Sim (servidor) | Sim (servidor) |
| Serialização | Automática | Manual (JSON) |
| Formulários nativos | Suporte total | Não aplicável |
| Código necessário | Menos | Mais |
Server Action com validação completa
Crie uma Server Action que realiza validação algorítmica antes de consultar a API:
// actions/cpf-actions.js
'use server';
function validarDigitosCpf(cpf) {
const digitos = cpf.split('').map(Number);
if (new Set(digitos).size === 1) return false;
let soma = 0;
for (let i = 0; i < 9; i++) soma += digitos[i] * (10 - i);
const d1 = soma % 11 < 2 ? 0 : 11 - (soma % 11);
soma = 0;
for (let i = 0; i < 10; i++) soma += digitos[i] * (11 - i);
const d2 = soma % 11 < 2 ? 0 : 11 - (soma % 11);
return digitos[9] === d1 && digitos[10] === d2;
}
export async function validarEConsultarCpf(formData) {
const cpf = formData.get('cpf');
const cpfLimpo = cpf.replace(/\D/g, '');
if (cpfLimpo.length !== 11) {
return {
success: false,
etapa: 'formato',
error: 'CPF deve conter 11 dígitos',
};
}
if (!validarDigitosCpf(cpfLimpo)) {
return {
success: false,
etapa: 'digitos',
error: 'Dígitos verificadores inválidos',
};
}
try {
const response = await fetch(
`${process.env.CPFHUB_BASE_URL}/cpf/${cpfLimpo}`,
{
headers: { 'x-api-key': process.env.CPFHUB_API_KEY },
}
);
if (!response.ok) {
return {
success: true,
etapa: 'api',
formatoValido: true,
encontrado: false,
message: 'CPF válido, porém não encontrado na base',
};
}
const dados = await response.json();
return {
success: true,
etapa: 'completa',
formatoValido: true,
encontrado: dados.success,
data: dados.success ? dados.data : null,
};
} catch {
return {
success: false,
etapa: 'api',
error: 'Erro ao consultar API externa',
};
}
}
Usando Server Actions com useActionState
O hook useActionState do React permite gerenciar o estado de Server Actions de forma elegante:
// components/CpfConsultaForm.jsx
'use client';
import { useActionState } from 'react';
import { validarEConsultarCpf } from '@/actions/cpf-actions';
const initialState = { success: null, data: null, error: null };
export default function CpfConsultaForm() {
const [state, formAction, isPending] = useActionState(
validarEConsultarCpf,
initialState
);
return (
<div className="max-w-lg mx-auto p-6">
<h2 className="text-xl font-bold mb-4">Consulta de CPF</h2>
<form action={formAction} className="space-y-4">
<div>
<label htmlFor="cpf" className="block text-sm font-medium mb-1">
CPF
</label>
<input
id="cpf"
name="cpf"
type="text"
maxLength={14}
placeholder="000.000.000-00"
required
className="w-full p-3 border rounded"
/>
</div>
<button
type="submit"
disabled={isPending}
className="w-full p-3 bg-blue-600 text-white rounded disabled:opacity-50"
>
{isPending ? 'Consultando...' : 'Consultar CPF'}
</button>
</form>
{state.success === true && state.data && (
<div className="mt-6 p-4 bg-green-50 border border-green-200 rounded">
<h3 className="font-bold mb-2">Dados encontrados</h3>
<p><strong>Nome:</strong> {state.data.name}</p>
<p><strong>CPF:</strong> {state.data.cpf}</p>
<p><strong>Nascimento:</strong> {state.data.birthDate}</p>
<p><strong>Genero:</strong> {state.data.gender}</p>
</div>
)}
{state.success === true && !state.encontrado && (
<div className="mt-6 p-4 bg-yellow-50 border border-yellow-200 rounded">
<p>{state.message}</p>
</div>
)}
{state.success === false && (
<div className="mt-6 p-4 bg-red-50 border border-red-200 rounded">
<p className="text-red-700">{state.error}</p>
</div>
)}
</div>
);
}
Server Action para processamento em lote
Crie uma Server Action que processa múltiplos CPFs:
// actions/cpf-lote-actions.js
'use server';
export async function processarLoteCpf(formData) {
const cpfsTexto = formData.get('cpfs');
const cpfs = cpfsTexto
.split('\n')
.map((l) => l.trim().replace(/\D/g, ''))
.filter((l) => l.length === 11);
if (cpfs.length === 0) {
return { success: false, error: 'Nenhum CPF válido encontrado' };
}
if (cpfs.length > 20) {
return { success: false, error: 'Máximo de 20 CPFs por lote' };
}
const resultados = await Promise.allSettled(
cpfs.map(async (cpf) => {
const response = await fetch(
`${process.env.CPFHUB_BASE_URL}/cpf/${cpf}`,
{
headers: { 'x-api-key': process.env.CPFHUB_API_KEY },
}
);
if (!response.ok) {
return { cpf, encontrado: false };
}
const dados = await response.json();
return {
cpf,
encontrado: dados.success,
nome: dados.success ? dados.data.name : null,
dataNascimento: dados.success ? dados.data.birthDate : null,
};
})
);
return {
success: true,
total: cpfs.length,
resultados: resultados.map((r) =>
r.status === 'fulfilled'
? r.value
: { cpf: 'desconhecido', encontrado: false, erro: 'Falha na consulta' }
),
};
}
Página completa com Server Actions
Monte a página que integra todos os componentes:
// app/consulta/page.jsx
import CpfConsultaForm from '@/components/CpfConsultaForm';
export const metadata = {
title: 'Consulta de CPF | Minha Aplicação',
description: 'Consulte dados de CPF de forma rápida e segura',
};
export default function ConsultaPage() {
return (
<main className="min-h-screen bg-gray-50 py-12">
<div className="container mx-auto">
<h1 className="text-3xl font-bold text-center mb-8">
Consulta de CPF
</h1>
<CpfConsultaForm />
</div>
</main>
);
}
Perguntas frequentes
O que são Server Actions no Next.js e como diferem de Route Handlers?
Server Actions são funções assíncronas marcadas com 'use server' que executam no servidor e podem ser chamadas diretamente de componentes React — inclusive em atributos action de formulários nativos. Diferente de Route Handlers (arquivos route.js), não exigem um endpoint HTTP separado: o Next.js serializa automaticamente a chamada, reduzindo boilerplate e mantendo a API key fora do bundle do cliente.
Como proteger a chave de API da CPFHub.io ao usar Server Actions?
Armazene a chave em variáveis de ambiente sem o prefixo NEXT_PUBLIC_ (por exemplo, CPFHUB_API_KEY). O Next.js nunca inclui variáveis sem esse prefixo no bundle do cliente. Como a Server Action executa apenas no servidor, a chave nunca é exposta ao navegador — mesmo que o componente que chama a action seja renderizado no cliente.
A API da CPFHub.io pode retornar erro 429 se eu ultrapassar o limite do plano gratuito?
Não. A API da CPFHub.io não retorna HTTP 429 nem bloqueia requisições ao atingir a cota do plano gratuito (50 consultas/mês). Consultas excedentes são cobradas automaticamente a R$0,15 cada. Para acompanhar o consumo e gerenciar o faturamento, acesse app.cpfhub.io/settings/billing.
Como usar useActionState com Server Actions para feedback visual?
Importe useActionState de 'react' e passe sua Server Action como primeiro argumento, seguido do estado inicial. O hook retorna [state, formAction, isPending]: state contém o retorno da última execução, formAction é passado ao atributo action do formulário e isPending indica se a action está em andamento — ideal para desabilitar o botão de submit durante a consulta. A documentação oficial do Next.js cobre o padrão completo com exemplos.
Conclusão
Server Actions do Next.js simplificam drasticamente a integração com APIs externas. Sem necessidade de Route Handlers, o código fica mais conciso e a chave de API permanece segura no servidor. A integração com useActionState proporciona gerenciamento de estado elegante e feedback visual automático durante o processamento.
Cadastre-se em cpfhub.io — 50 consultas mensais gratuitas, sem cartão de crédito — e comece a usar Server Actions com validação de CPF em minutos, sem configurar nenhum endpoint de API.
CPFHub.io
Pronto para integrar a API?
50 consultas gratuitas para testar agora. Sem cartão de crédito. Acesso imediato à documentação.
Sobre a redação
Redação CPFHub.io
Time editorial especializado em APIs de CPF, identidade digital e compliance no mercado brasileiro. Produzimos guias técnicos, análises regulatórias e tutoriais sobre LGPD e KYC para desenvolvedores e líderes de produto.



