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.

Redação CPFHub.io
Redação CPFHub.io
··7 min de leitura
Como consumir API de CPF em SvelteKit com load functions e 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

// 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 para a referência completa de form actions:

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

<!-- 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:

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

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

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óduloServidorClienteTipo
$env/static/privateSimNãoEstático
$env/static/publicSimSimEstático
$env/dynamic/privateSimNãoDinâmico
$env/dynamic/publicSimSimDinâ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.


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 direta e segura.

Cadastre-se em cpfhub.io

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