# 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.

**Publicado:** 25/04/2026
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/como-integrar-validacao-de-cpf-em-aplicacoes-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](https://www.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**](https://www.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`:

```typescript
// 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:

```typescript
// 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:

```typescript
// 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**](https://www.cpfhub.io/) retorna um JSON padronizado em todas as consultas:

```json
{
 "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:

```typescript
// 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:

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

---

## 8. Boas práticas

* **Server-only** — `routeLoader$`, `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](https://www.gov.br/anpd) recomenda que dados de identificação sejam tratados com base legal clara — o que se aplica tanto em desenvolvimento quanto em produção.

### Leia também

- [Como validar CPF no frontend com React e API REST](https://cpfhub.io/blog/como-validar-cpf-no-frontend-com-react-e-api-rest)
- [Como consumir API de CPF em TypeScript com tipagem segura](https://cpfhub.io/blog/como-consumir-api-de-cpf-em-typescript-com-tipagem-segura)
- [Boas práticas para consumir APIs de CPF de forma segura](https://cpfhub.io/blog/boas-praticas-consumir-apis-cpf-segura)
- [Autenticação em APIs REST: como garantir segurança na consulta de CPF](https://cpfhub.io/blog/autenticacao-apis-rest-seguranca-consulta-cpf)

---

## 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](https://www.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.

