# Como consumir API de CPF em SvelteKit com load functions e form actions

> Aprenda a integrar a API de consulta de CPF em SvelteKit usando load functions para SSR e form actions para validação server-side segura.

**Publicado:** 13/09/2026
**Autor:** Redação CPFHub.io
**URL:** https://www.cpfhub.io/blog/como-consumir-api-cpf-sveltekit-load-functions-form-actions

---


SvelteKit é o framework full-stack do ecossistema Svelte que combina renderização server-side, roteamento baseado em arquivos e um modelo de dados elegante com load functions e form actions. Para integrar a API de CPF da CPFHub.io, a chave de API fica protegida em `+page.server.ts` — nunca exposta ao cliente — enquanto o formulário funciona com ou sem JavaScript graças ao mecanismo de form actions.

---

## Estrutura do projeto SvelteKit

O SvelteKit utiliza roteamento baseado em arquivos. Para nossa integração com a API de CPF, criaremos a seguinte estrutura:

```
src/
 lib/
 server/
 cpfhub.ts # Servico de consulta (server-only)
 routes/
 consulta-cpf/
 +page.svelte # Interface do formulario
 +page.server.ts # Load function e form actions
```

A separação entre `+page.svelte` (frontend) e `+page.server.ts` (backend) é fundamental. O arquivo `+page.server.ts` executa exclusivamente no servidor, garantindo que a chave de API nunca seja exposta ao cliente.

---

## Serviço de consulta no servidor

Primeiro, criamos o módulo que encapsula a comunicação com a API da [**CPFHub.io**](https://www.cpfhub.io/)

```typescript
// src/lib/server/cpfhub.ts
import { CPFHUB_API_KEY } from "$env/static/private";

interface CPFData {
 cpf: string;
 name: string;
 nameUpper: string;
 gender: string;
 birthDate: string;
 day: number;
 month: number;
 year: number;
}

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 digitos");
 }

 const controller = new AbortController();
 const timeout = setTimeout(() => controller.abort(), 10000);

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

 clearTimeout(timeout);

 if (!response.ok) {
 throw new Error(`API retornou status ${response.status}`);
 }

 return await response.json();
 } catch (error) {
 clearTimeout(timeout);
 if (error instanceof Error && error.name === "AbortError") {
 throw new Error("Timeout na consulta de CPF");
 }
 throw error;
 }
}
```

Note o uso de `$env/static/private` — um recurso do SvelteKit que garante que variáveis de ambiente privadas nunca sejam acessíveis no cliente. A chave `CPFHUB_API_KEY` deve estar no arquivo `.env` do projeto.

---

## Form action para processar a consulta

O form action é o mecanismo do SvelteKit para processar formulários no servidor. Ele funciona mesmo sem JavaScript habilitado no navegador, o que melhora a acessibilidade e a resiliência da aplicação. Consulte a [documentação oficial do SvelteKit](https://kit.svelte.dev/docs/form-actions) para a referência completa de form actions:

```typescript
// src/routes/consulta-cpf/+page.server.ts
import type { Actions, PageServerLoad } from "./$types";
import { fail } from "@sveltejs/kit";
import { consultarCPF } from "$lib/server/cpfhub";

export const load: PageServerLoad = async () => {
 return {
 titulo: "Consulta de CPF",
 descricao: "Informe o CPF para consultar os dados cadastrais."
 };
};

export const actions: Actions = {
 consultar: async ({ request }) => {
 const formData = await request.formData();
 const cpf = formData.get("cpf")?.toString() ?? "";

 // Validacao basica no servidor
 const cpfLimpo = cpf.replace(/\D/g, "");

 if (cpfLimpo.length !== 11) {
 return fail(400, {
 cpf,
 erro: "CPF invalido. Informe 11 digitos."
 });
 }

 try {
 const resultado = await consultarCPF(cpfLimpo);

 if (!resultado.success || !resultado.data) {
 return fail(404, {
 cpf,
 erro: "CPF nao encontrado na base de dados."
 });
 }

 return {
 cpf,
 sucesso: true,
 dados: {
 nome: resultado.data.name,
 genero: resultado.data.gender,
 dataNascimento: resultado.data.birthDate
 }
 };
 } catch (error) {
 const mensagem = error instanceof Error
 ? error.message
 : "Erro desconhecido";

 return fail(500, {
 cpf,
 erro: `Falha na consulta: ${mensagem}`
 });
 }
 }
};
```

O form action `consultar` valida o CPF, chama a API e retorna os dados ou uma mensagem de erro. O uso de `fail()` permite retornar erros com status HTTP apropriados.

---

## Interface com Svelte

O componente Svelte renderiza o formulário e exibe os resultados. O SvelteKit cuida da comunicação com o form action automaticamente:

```svelte
<!-- src/routes/consulta-cpf/+page.svelte -->
<script lang="ts">
 import type { PageData, ActionData } from "./$types";
 import { enhance } from "$app/forms";

 export let data: PageData;
 export let form: ActionData;

 let carregando = false;

 function formatarCPF(valor: string): string {
 const digitos = valor.replace(/\D/g, "").slice(0, 11);
 if (digitos.length <= 3) return digitos;
 if (digitos.length <= 6) return `${digitos.slice(0, 3)}.${digitos.slice(3)}`;
 if (digitos.length <= 9)
 return `${digitos.slice(0, 3)}.${digitos.slice(3, 6)}.${digitos.slice(6)}`;
 return `${digitos.slice(0, 3)}.${digitos.slice(3, 6)}.${digitos.slice(6, 9)}-${digitos.slice(9)}`;
 }

 let cpfInput = form?.cpf ?? "";

 function handleInput(event: Event) {
 const target = event.target as HTMLInputElement;
 cpfInput = formatarCPF(target.value);
 target.value = cpfInput;
 }
</script>

<svelte:head>
 <title>{data.titulo}</title>
</svelte:head>

<main>
 <h2>{data.titulo}</h2>
 <p>{data.descricao}</p>

 <form
 method="POST"
 action="?/consultar"
 use:enhance={() => {
 carregando = true;
 return async ({ update }) => {
 carregando = false;
 await update();
 };
 }}
 >
 <label for="cpf">CPF:</label>
 <input
 id="cpf"
 name="cpf"
 type="text"
 value={cpfInput}
 on:input={handleInput}
 placeholder="000.000.000-00"
 maxlength="14"
 required
 />

 <button type="submit" disabled={carregando}>
 {carregando ? "Consultando..." : "Consultar CPF"}
 </button>
 </form>

 {#if form?.erro}
 <div class="erro" role="alert">
 <p>{form.erro}</p>
 </div>
 {/if}

 {#if form?.sucesso && form?.dados}
 <div class="resultado">
 <h3>Dados encontrados</h3>
 <dl>
 <dt>Nome</dt>
 <dd>{form.dados.nome}</dd>
 <dt>Genero</dt>
 <dd>{form.dados.genero === "M" ? "Masculino" : "Feminino"}</dd>
 <dt>Data de nascimento</dt>
 <dd>{form.dados.dataNascimento}</dd>
 </dl>
 </div>
 {/if}
</main>
```

O `use:enhance` transforma o formulário em uma experiência de SPA quando JavaScript está disponível, mas o formulário continua funcionando sem JavaScript — o SvelteKit faz o POST tradicional e re-renderiza a página.

---

## Adicionando validação com Zod

Para validações mais robustas, podemos integrar Zod no form action:

```typescript
// src/routes/consulta-cpf/schema.ts
import { z } from "zod";

export const cpfSchema = z.object({
 cpf: z
 .string()
 .transform((val) => val.replace(/\D/g, ""))
 .refine((val) => val.length === 11, "CPF deve ter 11 digitos")
 .refine((val) => !/^(\d)\1+$/.test(val), "CPF invalido")
});
```

E no form action, substituímos a validação manual:

```typescript
// Dentro do form action
const parsed = cpfSchema.safeParse({ cpf });

if (!parsed.success) {
 return fail(400, {
 cpf,
 erro: parsed.error.errors[0].message
 });
}

const resultado = await consultarCPF(parsed.data.cpf);
```

---

## Proteção com rate limiting

Para evitar abusos na sua própria aplicação, implemente rate limiting no form action usando um Map simples ou uma solução como `sveltekit-rate-limiter`:

```typescript
const tentativas = new Map<string, { count: number; resetAt: number }>();

function verificarRateLimit(ip: string): boolean {
 const agora = Date.now();
 const registro = tentativas.get(ip);

 if (!registro || registro.resetAt < agora) {
 tentativas.set(ip, { count: 1, resetAt: agora + 60000 });
 return true;
 }

 if (registro.count >= 5) {
 return false;
 }

 registro.count++;
 return true;
}
```

---

## Variáveis de ambiente no SvelteKit

O SvelteKit oferece quatro módulos para variáveis de ambiente:

| Módulo | Servidor | Cliente | Tipo |
|-----------------------------|----------|---------|----------|
| `$env/static/private` | Sim | Não | Estático |
| `$env/static/public` | Sim | Sim | Estático |
| `$env/dynamic/private` | Sim | Não | Dinâmico |
| `$env/dynamic/public` | Sim | Sim | Dinâmico |

Para a chave de API da CPFHub.io, use sempre `$env/static/private` ou `$env/dynamic/private`. Nunca exponha a chave no cliente.

---

## Perguntas frequentes

### Como o SvelteKit protege a chave de API da CPFHub.io?

O arquivo `+page.server.ts` executa exclusivamente no servidor — nunca no navegador. Ao importar a chave via `$env/static/private`, o SvelteKit garante em tempo de build que essa variável não vaze para o bundle do cliente. A chave fica segura mesmo em aplicações SSR ou com hydration ativa.

### O formulário de consulta de CPF funciona sem JavaScript?

Sim. O mecanismo de form actions do SvelteKit funciona como um POST HTML tradicional quando o JavaScript não está disponível. O `use:enhance` é uma progressiva enhancement: ele melhora a experiência em browsers modernos, mas o fluxo de validação server-side funciona de qualquer forma.

### Como tratar erros de timeout na chamada à API de CPF?

A latência da CPFHub.io é de aproximadamente 900ms. Defina o timeout do `AbortController` em 10 segundos para cobrir variações de rede sem impactar o usuário. No form action, capture o `AbortError` e retorne um `fail(500, { erro: "Timeout na consulta" })` — o SvelteKit re-renderiza o formulário com a mensagem de erro automaticamente.

### Como limitar o número de consultas por usuário no SvelteKit?

Implemente rate limiting no form action usando o IP do cliente (disponível em `request.headers.get("x-forwarded-for")`). Uma estrutura `Map<string, { count, resetAt }>` resolve o caso básico. Para produção com múltiplas instâncias, use Redis ou um KV store distribuído — o pacote `sveltekit-rate-limiter` abstrai essa lógica.

### Leia também

- [API de CPF grátis para desenvolvedores: como começar em 5 minutos](https://cpfhub.io/blog/api-cpf-gratis-desenvolvedores-comecar-5-minutos)
- [Como implementar cache inteligente em respostas de API de CPF](https://cpfhub.io/blog/como-implementar-cache-inteligente-respostas-api-cpf)
- [Como implementar retry e backoff exponencial em consultas de API de CPF](https://cpfhub.io/blog/como-implementar-retry-backoff-exponencial-consultas-api-cpf)
- [Diferença entre validação de CPF e consulta de CPF: quando usar cada uma](https://cpfhub.io/blog/diferenca-entre-validacao-de-cpf-e-consulta-de-cpf-quando-usar-cada-uma)

---

## Conclusão

O SvelteKit oferece uma combinação poderosa de load functions e form actions que torna a integração com APIs externas como a [**CPFHub.io**](https://www.cpfhub.io/) direta e segura.

Cadastre-se em [cpfhub.io](https://www.cpfhub.io/)

