Como integrar validação de CPF em aplicações Qwik com routeLoader$

Aprenda a integrar a API de consulta de CPF da CPFHub.io em aplicações Qwik usando routeLoader$ e routeAction$ para validação server-side.

Redação CPFHub.io
Redação CPFHub.io
··7 min de leitura
Como integrar validação de CPF em aplicações Qwik com routeLoader$

Para integrar validação de CPF em uma aplicação Qwik, use routeLoader$ para consultas server-side por parâmetro de URL e routeAction$ para processar submissões de formulário. A chave de API fica exclusivamente no servidor — nunca exposta ao cliente — e a resposta da CPFHub.io chega em cerca de 900ms com nome, data de nascimento e gênero do titular.


1. Pré-requisitos

  • Qwik configurado com npm create qwik@latest.

  • Node.js 18+ instalado.

  • Uma conta na CPFHub.io com sua chave de API gerada em app.cpfhub.io.


2. Configure a variável de ambiente

Crie o arquivo .env na raiz do projeto:

CPFHUB_API_KEY=SUA_CHAVE_DE_API

O Qwik usa Vite, que carrega variáveis prefixadas com VITE_ no cliente. Como a chave de API deve ficar no servidor, use o prefixo sem VITE_ e acesse via process.env nos loaders e actions (que rodam no servidor).


3. Função utilitária de consulta

Crie o arquivo src/lib/cpfhub.ts:

// src/lib/cpfhub.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;
    }
}

4. Validação com routeLoader$

O routeLoader$ executa no servidor antes da renderização. Use-o para consultar um CPF passado na URL:

// src/routes/cpf/[cpf]/index.tsx
import { component$ } from '@builder.io/qwik';
import { routeLoader$ } from '@builder.io/qwik-city';
import { consultarCpf } from '~/lib/cpfhub';

export const useCpfData = routeLoader$(async (requestEvent) => {
    const cpf = requestEvent.params.cpf;

    try {
    const resultado = await consultarCpf(cpf);
    return { success: true, data: resultado.data, error: null };
    } catch (error) {
    return {
    success: false,
    data: null,
    error: error instanceof Error ? error.message : 'Erro desconhecido'
    };
    }
});

export default component$(() => {
    const cpfData = useCpfData();

    return (
    <div>
    <h2>Resultado da validação</h2>

    {cpfData.value.error && (
    <p style="color: red;">{cpfData.value.error}</p>
    )}

    {cpfData.value.success && cpfData.value.data && (
    <dl>
    <dt>CPF</dt>
    <dd>{cpfData.value.data.cpf}</dd>
    <dt>Nome</dt>
    <dd>{cpfData.value.data.name}</dd>
    <dt>Gênero</dt>
    <dd>{cpfData.value.data.gender === 'M' ? 'Masculino' : 'Feminino'}</dd>
    <dt>Data de nascimento</dt>
    <dd>{cpfData.value.data.birthDate}</dd>
    </dl>
    )}
    </div>
    );
});

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


5. Validação com routeAction$ (formulário)

O routeAction$ processa submissões de formulário no servidor:

// src/routes/validar/index.tsx
import { component$ } from '@builder.io/qwik';
import { routeAction$, Form, zod$, z } from '@builder.io/qwik-city';
import { consultarCpf } from '~/lib/cpfhub';

export const useValidarCpf = routeAction$(
    async (formData) => {
    const cpf = formData.cpf;

    try {
    const resultado = await consultarCpf(cpf);

    if (resultado.success) {
    return {
    success: true,
    nome: resultado.data.name,
    cpf: resultado.data.cpf,
    genero: resultado.data.gender,
    nascimento: resultado.data.birthDate
    };
    }

    return { success: false, error: 'CPF não encontrado' };
    } catch (error) {
    return {
    success: false,
    error: error instanceof Error ? error.message : 'Erro na consulta'
    };
    }
    },
    zod$({
    cpf: z.string().min(11, 'CPF deve conter pelo menos 11 caracteres')
    })
);

export default component$(() => {
    const action = useValidarCpf();

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

    <Form action={action}>
    <label for="cpf">CPF:</label>
    <input
    type="text"
    id="cpf"
    name="cpf"
    placeholder="Digite o CPF"
    maxLength={14}
    required
    />
    <button type="submit" disabled={action.isRunning}>
    {action.isRunning ? 'Consultando...' : 'Validar'}
    </button>
    </Form>

    {action.value?.error && (
    <p style="color: red;">{action.value.error}</p>
    )}

    {action.value?.success && (
    <dl>
    <dt>Nome</dt>
    <dd>{action.value.nome}</dd>
    <dt>CPF</dt>
    <dd>{action.value.cpf}</dd>
    <dt>Data de nascimento</dt>
    <dd>{action.value.nascimento}</dd>
    </dl>
    )}
    </div>
    );
});

6. Exemplo de resposta da API

A API da CPFHub.io retorna um JSON padronizado em todas as consultas:

{
    "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. Endpoint de API puro

Se você precisa de um endpoint REST no Qwik (sem interface visual), crie um handler:

// src/routes/api/cpf/[cpf]/index.ts
import type { RequestHandler } from '@builder.io/qwik-city';
import { consultarCpf } from '~/lib/cpfhub';

export const onGet: RequestHandler = async ({ params, json }) => {
    const cpf = params.cpf;

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

Teste com:

curl -X GET http://localhost:5173/api/cpf/12345678900 \
    -H "Accept: application/json"

8. Boas práticas

  • Server-onlyrouteLoader$, routeAction$ e onGet rodam exclusivamente no servidor. A chave de API nunca é enviada ao cliente.

  • Timeout — O AbortController com 5 segundos impede que consultas lentas travem a renderização.

  • Validação com Zod — Use zod$ no routeAction$ para validar dados do formulário antes de consultar a API.

  • Loading state — O Qwik expõe action.isRunning para mostrar feedback ao usuário durante a consulta.

  • Plano gratuito — O plano gratuito oferece 50 consultas/mês. Ao ultrapassar o limite, a API não bloqueia: cobra R$0,15 por consulta adicional. Para produção, o plano Pro inclui 1.000 consultas por R$149/mês.


Perguntas frequentes

Como o routeLoader$ difere de um fetch direto no componente Qwik?

O routeLoader$ executa no servidor antes da renderização, garantindo que a chave de API nunca seja exposta ao cliente. Um fetch direto no componente rodaria no browser e exporia credenciais. Além disso, o loader permite pré-carregar dados para o componente antes de ele ser renderizado, melhorando a performance percebida.

A latência da API impacta a performance do Qwik?

A CPFHub.io responde em aproximadamente 900ms. Como o routeLoader$ roda no servidor (onde a latência de rede é menor do que a do usuário final), o impacto na experiência é reduzido. Use o AbortController com timeout de 5 segundos como proteção contra casos excepcionais de lentidão.

Como tratar o caso em que a API retorna erro no routeLoader$?

Envolva a chamada em try/catch e retorne um objeto com success: false e uma mensagem de erro. O componente pode checar cpfData.value.error para exibir feedback ao usuário — sem lançar exceções que interromperiam a renderização da página inteira.

O plano gratuito é suficiente para rodar a integração em desenvolvimento?

Sim. O plano gratuito oferece 50 consultas mensais sem cartão de crédito, o que cobre com folga o desenvolvimento e os testes iniciais. A ANPD recomenda que dados de identificação sejam tratados com base legal clara — o que se aplica tanto em desenvolvimento quanto em produção.


Conclusão

O Qwik com routeLoader$ e routeAction$ oferece uma forma segura e eficiente de integrar a API da CPFHub.io. A separação clara entre código de servidor e cliente elimina o risco de vazamento de credenciais, enquanto a abordagem de resumabilidade do Qwik garante que apenas o JavaScript necessário seja carregado no browser.

Para começar, crie sua conta gratuita em cpfhub.io, gere sua chave de API e siga os exemplos deste artigo. O plano gratuito cobre o desenvolvimento completo — você só escala para um plano pago quando seu produto estiver em produção com volume real.

CPFHub.io

Pronto para integrar a API?

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

Redação CPFHub.io

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.

WhatsAppFale conosco via WhatsApp