Como validar CPF em aplicações Svelte e SvelteKit

Aprenda a integrar validação de CPF em aplicações Svelte e SvelteKit usando a API do CPFHub.io, com exemplos de componentes e server routes.

Redação CPFHub.io
Redação CPFHub.io
··8 min de leitura
Como validar CPF em aplicações Svelte e SvelteKit

Para validar CPF em aplicações Svelte e SvelteKit, crie uma server route em src/routes/api/cpf/[cpf]/+server.ts que chama a API do CPFHub.io com o header x-api-key — mantendo a chave segura no servidor via $env/static/private — e consuma esse endpoint no componente Svelte com validação local dos dígitos antes da requisição. O resultado é um fluxo de validação completo, com progressive enhancement via form actions e feedback visual em tempo real.

Introdução

O Svelte e o SvelteKit vêm ganhando adoção significativa entre desenvolvedores web, oferecendo uma abordagem compilada que resulta em aplicações mais leves e rápidas que frameworks tradicionais. Para projetos brasileiros que utilizam Svelte, a validação de CPF é uma funcionalidade recorrente -- seja em formulários de cadastro, checkout de e-commerce ou sistemas internos de gestão.


Pré-requisitos

  • Node.js 18+ -- Necessário para rodar o SvelteKit.

  • Projeto SvelteKit -- Se ainda não tem, crie um com npm create svelte@latest.

  • Conta no CPFHub.io -- Crie uma conta gratuita em cpfhub.io

Configuração do ambiente

Crie um arquivo .env na raiz do projeto:

CPFHUB_API_KEY=SUA_CHAVE_DE_API

Entendendo a API

Para referência, a chamada à API do CPFHub.io:

curl -X GET https://api.cpfhub.io/cpf/12345678900 \
    -H "x-api-key: SUA_CHAVE_DE_API" \
    -H "Accept: application/json"

Resposta:

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

Server route para consulta de CPF

No SvelteKit, as server routes (arquivos +server.ts ou +server.js) executam no servidor, protegendo a chave de API. Crie o arquivo src/routes/api/cpf/[cpf]/+server.ts:

import { json, error } from '@sveltejs/kit';
import { CPFHUB_API_KEY } from '$env/static/private';
import type { RequestHandler } from './$types';

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

interface CPFHubResponse {
    success: boolean;
    data?: CPFData;
}

export const GET: RequestHandler = async ({ params }) => {
    const cpf = params.cpf.replace(/\D/g, '');

    if (cpf.length !== 11) {
    throw error(400, 'CPF deve ter 11 dígitos');
    }

    try {
    const response = await fetch(
    `https://api.cpfhub.io/cpf/${cpf}`,
    {
    headers: {
    'x-api-key': CPFHUB_API_KEY,
    'Accept': 'application/json'
    },
    signal: AbortSignal.timeout(10000)
    }
    );

    if (response.status === 401) {
    throw error(500, 'Erro de configuração da API');
    }

    const dados: CPFHubResponse = await response.json();

    if (!dados.success) {
    throw error(404, 'CPF não encontrado');
    }

    return json({
    success: true,
    data: dados.data
    });

    } catch (err) {
    if (err && typeof err === 'object' && 'status' in err) {
    throw err;
    }
    throw error(500, 'Falha na consulta de CPF');
    }
};

Componente Svelte de validação de CPF

Crie o componente src/lib/components/CPFValidator.svelte:

<script lang="ts">
    let cpf = '';
    let resultado: {
    nome?: string;
    nascimento?: string;
    genero?: string;
    } | null = null;
    let erro = '';
    let carregando = false;

    function formatarCPF(valor: string): string {
    const numeros = valor.replace(/\D/g, '').substring(0, 11);
    if (numeros.length > 9) {
    return numeros.replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, '$1.$2.$3-$4');
    } else if (numeros.length > 6) {
    return numeros.replace(/(\d{3})(\d{3})(\d{1,3})/, '$1.$2.$3');
    } else if (numeros.length > 3) {
    return numeros.replace(/(\d{3})(\d{1,3})/, '$1.$2');
    }
    return numeros;
    }

    function handleInput(event: Event) {
    const input = event.target as HTMLInputElement;
    cpf = formatarCPF(input.value);
    resultado = null;
    erro = '';
    }

    async function validarCPF() {
    const cpfLimpo = cpf.replace(/\D/g, '');

    if (cpfLimpo.length !== 11) {
    erro = 'CPF deve ter 11 dígitos.';
    return;
    }

    carregando = true;
    erro = '';
    resultado = null;

    try {
    const response = await fetch(`/api/cpf/${cpfLimpo}`);
    const dados = await response.json();

    if (response.ok && dados.success) {
    resultado = {
    nome: dados.data.name,
    nascimento: dados.data.birthDate,
    genero: dados.data.gender === 'M' ? 'Masculino' : 'Feminino'
    };
    } else {
    erro = dados.message || 'CPF não encontrado.';
    }
    } catch (e) {
    erro = 'Erro ao validar CPF. Tente novamente.';
    } finally {
    carregando = false;
    }
    }
</script>

<div class="cpf-validator">
    <label for="cpf-input">CPF</label>
    <div class="input-group">
    <input
    id="cpf-input"
    type="text"
    value={cpf}
    on:input={handleInput}
    placeholder="000.000.000-00"
    inputmode="numeric"
    maxlength="14"
    />
    <button on:click={validarCPF} disabled={carregando}>
    {carregando ? 'Validando...' : 'Validar'}
    </button>
    </div>

    {#if erro}
    <p class="erro">{erro}</p>
    {/if}

    {#if resultado}
    <div class="resultado">
    <p><strong>Nome:</strong> {resultado.nome}</p>
    <p><strong>Nascimento:</strong> {resultado.nascimento}</p>
    <p><strong>Gênero:</strong> {resultado.genero}</p>
    </div>
    {/if}
</div>

<style>
    .cpf-validator {
    max-width: 400px;
    }
    .input-group {
    display: flex;
    gap: 8px;
    }
    input {
    flex: 1;
    padding: 8px 12px;
    border: 1px solid #ccc;
    border-radius: 6px;
    font-size: 16px;
    }
    button {
    padding: 8px 16px;
    background: #2563eb;
    color: white;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    }
    button:disabled {
    opacity: 0.6;
    cursor: not-allowed;
    }
    .erro {
    color: #dc2626;
    margin-top: 8px;
    }
    .resultado {
    margin-top: 12px;
    padding: 12px;
    background: #f0fdf4;
    border: 1px solid #22c55e;
    border-radius: 6px;
    }
</style>

Usando o componente em uma página

Crie ou edite src/routes/cadastro/+page.svelte:

<script>
    import CPFValidator from '$lib/components/CPFValidator.svelte';
</script>

<h1>Cadastro</h1>
<CPFValidator />

Validação com SvelteKit form actions

Para formulários que usam form actions (progressive enhancement), crie src/routes/cadastro/+page.server.ts:

import { fail } from '@sveltejs/kit';
import { CPFHUB_API_KEY } from '$env/static/private';
import type { Actions } from './$types';

export const actions: Actions = {
    validar: async ({ request }) => {
    const formData = await request.formData();
    const cpf = (formData.get('cpf') as string).replace(/\D/g, '');

    if (cpf.length !== 11) {
    return fail(400, { cpf, erro: 'CPF deve ter 11 dígitos' });
    }

    try {
    const response = await fetch(
    `https://api.cpfhub.io/cpf/${cpf}`,
    {
    headers: {
    'x-api-key': CPFHUB_API_KEY,
    'Accept': 'application/json'
    },
    signal: AbortSignal.timeout(10000)
    }
    );

    const dados = await response.json();

    if (!dados.success) {
    return fail(404, { cpf, erro: 'CPF não encontrado' });
    }

    return {
    sucesso: true,
    dados: dados.data
    };

    } catch (e) {
    return fail(500, { cpf, erro: 'Falha na validação' });
    }
    }
};

Validação local com store reativo

Crie um store Svelte para validação local de CPF em src/lib/stores/cpf.ts:

import { writable, derived } from 'svelte/store';

export const cpfInput = writable('');

export const cpfLimpo = derived(cpfInput, ($cpf) =>
    $cpf.replace(/\D/g, '')
);

export const cpfValido = derived(cpfLimpo, ($cpf) => {
    if ($cpf.length !== 11) return false;
    if (/^(\d)\1{10}$/.test($cpf)) return false;

    let soma = 0;
    for (let i = 0; i < 9; i++) {
    soma += parseInt($cpf[i]) * (10 - i);
    }
    let resto = (soma * 10) % 11;
    if (resto === 10) resto = 0;
    if (resto !== parseInt($cpf[9])) return false;

    soma = 0;
    for (let i = 0; i < 10; i++) {
    soma += parseInt($cpf[i]) * (11 - i);
    }
    resto = (soma * 10) % 11;
    if (resto === 10) resto = 0;
    if (resto !== parseInt($cpf[10])) return false;

    return true;
});

Boas práticas

  • Chave de API no servidor -- Use $env/static/private do SvelteKit para garantir que a chave nunca seja exposta no cliente.

  • Validação em camadas -- Valide os dígitos localmente no componente antes de chamar a server route.

  • Progressive enhancement -- Use form actions para que o formulário funcione mesmo sem JavaScript habilitado.

  • Feedback visual -- Mostre estados de carregamento, sucesso e erro de forma clara para o usuário.

  • Controle de consumo -- Desabilite o botão durante o carregamento para evitar requisições duplicadas. O CPFHub.io não bloqueia ao atingir o limite do plano — cobra R$0,15 por consulta adicional —, então evitar requisições desnecessárias protege tanto a experiência quanto o orçamento.


Perguntas frequentes

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

O SvelteKit separa código de servidor e cliente em tempo de build. Ao importar a chave via $env/static/private, o compilador garante que ela nunca seja incluída no bundle enviado ao navegador. Qualquer tentativa de usar uma variável static/private em um componente .svelte gera erro em tempo de build — uma proteção automática e auditável.

Posso usar a validação de CPF diretamente no componente Svelte, sem server route?

Não é recomendado. Chamar a API do CPFHub.io diretamente do frontend exporia sua chave de API ao navegador. A server route atua como proxy seguro: o componente Svelte chama /api/cpf/{cpf} (sua rota interna), e apenas o servidor conhece a x-api-key. Essa arquitetura também permite adicionar cache e rate limiting no servidor sem tocar no componente.

O componente funciona sem JavaScript habilitado no navegador?

Sim, quando implementado com form actions (o arquivo +page.server.ts). O SvelteKit suporta progressive enhancement nativamente: sem JavaScript, o formulário faz um POST tradicional e recebe a resposta do servidor; com JavaScript, a ação é interceptada e o resultado é exibido de forma reativa sem recarregar a página.

Como armazenar o resultado da validação de CPF no estado global da aplicação Svelte?

Use o store reativo cpfInput e cpfValido demonstrados acima como ponto de partida. Para estado global mais complexo — como compartilhar o resultado de validação entre múltiplos componentes —, armazene o objeto data retornado pela API em um writable store e acesse-o via $cpfStore em qualquer componente que importe o store. Consulte a documentação oficial do SvelteKit para padrões recomendados de gerenciamento de estado.


Conclusão

O Svelte e o SvelteKit oferecem uma experiência de desenvolvimento fluida para integrar validação de CPF, com componentes reativos, server routes seguras e form actions com progressive enhancement. A API do CPFHub.io complementa esse stack com um endpoint simples, resposta em ~900ms e planos que escalam do desenvolvimento à produção sem mudanças de código.

Cadastre-se em cpfhub.io — 50 consultas mensais gratuitas, sem cartão de crédito — e adicione validação de CPF ao seu projeto Svelte em menos de 30 minutos.

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