Como integrar validação de CPF em aplicações Remix com loaders

Aprenda a integrar a API de consulta de CPF da CPFHub.io em aplicações Remix usando loaders e actions para validação server-side.

Lucas Vieira
Lucas Vieira
··7 min de leitura
Como integrar validação de CPF em aplicações Remix com loaders

Para integrar validação de CPF em aplicações Remix, use um módulo .server.ts para centralizar a chamada à API da CPFHub.io com a chave de autenticação no header x-api-key, depois exponha os dados via loader (consulta por URL) ou via action (formulário POST). A chave nunca chega ao navegador, e o log de cada consulta fica disponível para auditoria no servidor.

1. Pré-requisitos

  • Remix (v2+) configurado com npx create-remix@latest.

  • A chave de API da CPFHub.io

  • Node.js 18+ (para suporte nativo a fetch).


2. Configure a variável de ambiente

Crie o arquivo .env na raiz do projeto:

CPFHUB_API_KEY=SUA_CHAVE_DE_API

3. Crie o serviço de consulta

Crie um módulo utilitário para centralizar a chamada à API:

// app/services/cpfhub.server.ts
export interface CpfData {
    cpf: string;
    name: string;
    nameUpper: string;
    gender: string;
    birthDate: string;
    day: number;
    month: number;
    year: number;
}

export interface CpfResponse {
    success: boolean;
    data: CpfData;
}

export async function consultarCpf(cpf: string): Promise<CpfResponse> {
    const cpfLimpo = cpf.replace(/\D/g, '');

    if (cpfLimpo.length !== 11) {
    throw new Error('CPF deve conter 11 dígitos');
    }

    const controller = new AbortController();
    const timeoutId = setTimeout(() => controller.abort(), 5000);

    try {
    const response = await fetch(`https://api.cpfhub.io/cpf/${cpfLimpo}`, {
    method: 'GET',
    headers: {
    'x-api-key': process.env.CPFHUB_API_KEY!,
    'Accept': 'application/json'
    },
    signal: controller.signal
    });

    clearTimeout(timeoutId);

    if (!response.ok) {
    if (response.status === 401) throw new Error('Chave de API inválida');
    throw new Error(`Erro HTTP ${response.status}`);
    }

    return await response.json();
    } catch (error) {
    clearTimeout(timeoutId);
    throw error;
    }
}

O sufixo .server.ts garante que esse código nunca será enviado ao navegador.


4. Validação via loader (consulta por URL)

Crie uma rota que recebe o CPF via parâmetro de URL e retorna os dados validados:

// app/routes/cpf.$cpf.tsx
import { json, type LoaderFunctionArgs } from '@remix-run/node';
import { useLoaderData } from '@remix-run/react';
import { consultarCpf } from '~/services/cpfhub.server';

export async function loader({ params }: LoaderFunctionArgs) {
    const cpf = params.cpf;

    if (!cpf) {
    throw new Response('CPF não informado', { status: 400 });
    }

    try {
    const resultado = await consultarCpf(cpf);
    return json(resultado);
    } catch (error) {
    throw new Response(
    error instanceof Error ? error.message : 'Erro na consulta',
    { status: 502 }
    );
    }
}

export default function CpfPage() {
    const resultado = useLoaderData<typeof loader>();

    return (
    <div>
    <h2>Resultado da validação</h2>
    {resultado.success ? (
    <dl>
    <dt>CPF</dt>
    <dd>{resultado.data.cpf}</dd>
    <dt>Nome</dt>
    <dd>{resultado.data.name}</dd>
    <dt>Gênero</dt>
    <dd>{resultado.data.gender === 'M' ? 'Masculino' : 'Feminino'}</dd>
    <dt>Data de nascimento</dt>
    <dd>{resultado.data.birthDate}</dd>
    </dl>
    ) : (
    <p>CPF não encontrado.</p>
    )}
    </div>
    );
}

Acesse http://localhost:3000/cpf/12345678900 para testar.


5. Validação via action (formulário)

Para cenários com formulário de entrada, use uma action:

// app/routes/validar-cpf.tsx
import { json, type ActionFunctionArgs } from '@remix-run/node';
import { Form, useActionData } from '@remix-run/react';
import { consultarCpf, type CpfResponse } from '~/services/cpfhub.server';

interface ActionData {
    resultado?: CpfResponse;
    error?: string;
}

export async function action({ request }: ActionFunctionArgs) {
    const formData = await request.formData();
    const cpf = formData.get('cpf') as string;

    if (!cpf) {
    return json<ActionData>({ error: 'CPF é obrigatório' }, { status: 400 });
    }

    try {
    const resultado = await consultarCpf(cpf);
    return json<ActionData>({ resultado });
    } catch (error) {
    return json<ActionData>({
    error: error instanceof Error ? error.message : 'Erro na consulta'
    }, { status: 502 });
    }
}

export default function ValidarCpfPage() {
    const data = useActionData<typeof action>();

    return (
    <div>
    <h2>Validar CPF</h2>

    <Form method="post">
    <label htmlFor="cpf">CPF:</label>
    <input
    type="text"
    id="cpf"
    name="cpf"
    placeholder="Digite o CPF"
    maxLength={14}
    required
    />
    <button type="submit">Validar</button>
    </Form>

    {data?.error && <p style={{ color: 'red' }}>{data.error}</p>}

    {data?.resultado?.success && (
    <dl>
    <dt>Nome</dt>
    <dd>{data.resultado.data.name}</dd>
    <dt>CPF</dt>
    <dd>{data.resultado.data.cpf}</dd>
    <dt>Data de nascimento</dt>
    <dd>{data.resultado.data.birthDate}</dd>
    </dl>
    )}
    </div>
    );
}

6. Exemplo de resposta da API

A API da CPFHub.io retorna um JSON estruturado com os dados do titular conforme registrado na Receita Federal:

{
    "success": true,
    "data": {
    "cpf": "12345678900",
    "name": "João da Silva",
    "nameUpper": "JOÃO DA SILVA",
    "gender": "M",
    "birthDate": "15/06/1990",
    "day": 15,
    "month": 6,
    "year": 1990
    }
}

7. Tratamento de erros com ErrorBoundary

O Remix permite tratar erros de loader e action com ErrorBoundary:

// Adicione no mesmo arquivo da rota
export function ErrorBoundary() {
    return (
    <div>
    <h2>Erro na validação</h2>
    <p>Não foi possível consultar o CPF. Tente novamente em alguns instantes.</p>
    </div>
    );
}

8. Boas práticas

  • Sufixo .server.ts — Use para módulos que contêm a chave de API, garantindo que o código nunca chegue ao cliente.

  • Timeout — O serviço usa AbortController com 5 segundos de timeout para evitar loaders travados. A latência média da API é de ~150 ms; dimensione o timeout com margem.

  • Validação local — Valide o formato do CPF (11 dígitos) antes de chamar a API para economizar consultas.

  • ErrorBoundary — Implemente ErrorBoundary em todas as rotas para exibir mensagens amigáveis ao usuário.

  • Cota e excedente — O plano gratuito da CPFHub.io inclui 50 créditos por mês. Esgotar a franquia do Grátis interrompe as consultas com HTTP 403 ("Limite de créditos excedido"). No plano pago, o excedente depende da faixa e está na página de preços. Acima do limite por minuto a resposta é HTTP 429, com Retry-After. Para volumes maiores, o plano Pro oferece 1.000 créditos/mês por R$ 149.


Perguntas frequentes

Como o Remix mantém a chave de API segura no servidor?

O sufixo .server.ts faz o Remix excluir automaticamente esse módulo do bundle do cliente durante o build. Isso garante que process.env.CPFHUB_API_KEY e a lógica de chamada à API jamais cheguem ao navegador. Qualquer tentativa de importar um módulo .server.ts em código de cliente resulta em erro de build antes do deploy.

Qual a diferença entre usar loader e action para validar CPF no Remix?

O loader é executado em requisições GET e é ideal quando o CPF vem como parâmetro de URL — por exemplo, em rotas de perfil ou verificação de cadastro. A action é executada em submissões de formulário (POST) e é a abordagem certa quando o usuário digita o CPF em um campo. Ambos rodam exclusivamente no servidor, portanto a chave de API nunca fica exposta.

Quanto tempo a API leva para responder e como isso afeta o loader?

A API da CPFHub.io tem latência média de ~150 ms. O loader do Remix aguarda a resolução da promessa antes de renderizar a página, então configure um timeout razoável — o exemplo acima usa 5 segundos via AbortController. Para não penalizar a UX em consultas lentas, considere usar defer do Remix para carregar os dados de CPF em paralelo com o restante da página.

Como garantir conformidade com a LGPD ao usar a API de CPF no Remix?

Use o CPF apenas para a finalidade declarada ao titular, armazene apenas o necessário nos logs do servidor e implemente controle de acesso a esses registros. A ANPD orienta que dados de identificação devem ser tratados com o princípio da necessidade. No Remix, evite serializar dados de CPF no loader além do estritamente necessário para a view — o que não é enviado ao cliente não pode ser exposto.


Conclusão

O Remix é uma escolha sólida para integrar APIs de validação como a CPFHub.io porque o modelo loader/action garante que a chave de API e a lógica sensível nunca abandonem o servidor. Com o módulo .server.ts, o timeout via AbortController e o ErrorBoundary configurado, você tem uma integração robusta pronta para produção em menos de uma hora.

Para começar agora, crie sua conta gratuita em cpfhub.io, gere a API key no painel e faça a primeira consulta. O plano gratuito inclui 50 consultas por mês sem cartão de crédito — suficiente para validar a integração completa antes de decidir por um plano pago.

CPFHub.io

Pronto para integrar a API?

50 créditos gratuitos para testar agora. Sem cartão de crédito. Acesso imediato à documentação.

WhatsAppFale conosco via WhatsApp