Como integrar validação de CPF em aplicações Tauri (Rust + web)

Aprenda a integrar validação de CPF em aplicações Tauri usando Rust no backend e JavaScript no frontend com a API da CPFHub.io.

Redação CPFHub.io
Redação CPFHub.io
··7 min de leitura
Como integrar validação de CPF em aplicações Tauri (Rust + web)

O Tauri é um framework para construção de aplicações desktop que combina um backend em Rust com um frontend web (HTML, CSS, JavaScript). Para integrar validação de CPF, a chamada à API da CPFHub.io é feita pelo backend Rust — mantendo a chave de API fora do alcance do webview — e o resultado é devolvido ao frontend via comando Tauri. A API responde em ~900ms com nome, data de nascimento e demais dados do titular ao receber GET https://api.cpfhub.io/cpf/{CPF} com o header x-api-key.


1. Pré-requisitos

  • Rust (rustup) e Node.js 18+ instalados.

  • Tauri CLI: cargo install tauri-cli.

  • Um projeto Tauri criado: cargo tauri init.

  • Uma conta gratuita na CPFHub.io


2. Adicione as dependências Rust

No Cargo.toml do projeto (dentro de src-tauri/), adicione as dependências necessárias:

[dependencies]
tauri = { version = "2", features = [] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
reqwest = { version = "0.12", features = ["json"] }
tokio = { version = "1", features = ["full"] }
dotenv = "0.15"

3. Configure as variáveis de ambiente

Crie um arquivo .env na pasta src-tauri/:

CPFHUB_API_KEY=SUA_CHAVE_DE_API
CPFHUB_BASE_URL=https://api.cpfhub.io
CPFHUB_TIMEOUT=5

4. Crie as structs de resposta

Defina as structs Rust para deserializar a resposta da API:

// src-tauri/src/cpfhub.rs
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
pub struct CpfResponse {
    pub success: bool,
    pub data: Option<CpfData>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CpfData {
    pub cpf: String,
    pub name: String,
    #[serde(rename = "nameUpper")]
    pub name_upper: String,
    pub gender: String,
    #[serde(rename = "birthDate")]
    pub birth_date: String,
    pub day: u32,
    pub month: u32,
    pub year: u32,
}

#[derive(Debug, Serialize)]
pub struct CpfError {
    pub message: String,
    pub status_code: u16,
}

5. Implemente o comando Tauri

Crie o comando que será invocado pelo frontend. Consulte a documentação do Tauri para referência completa sobre comandos:

// src-tauri/src/cpfhub.rs (continuação)
use reqwest::Client;
use std::time::Duration;
use std::env;

pub async fn consultar_cpf(cpf: &str) -> Result<CpfData, CpfError> {
    let cpf_limpo: String = cpf.chars().filter(|c| c.is_ascii_digit()).collect();

    if cpf_limpo.len() != 11 {
    return Err(CpfError {
    message: "CPF deve conter exatamente 11 dígitos".to_string(),
    status_code: 400,
    });
    }

    let api_key = env::var("CPFHUB_API_KEY").map_err(|_| CpfError {
    message: "Chave de API não configurada".to_string(),
    status_code: 500,
    })?;

    let base_url = env::var("CPFHUB_BASE_URL")
    .unwrap_or_else(|_| "https://api.cpfhub.io".to_string());

    let timeout: u64 = env::var("CPFHUB_TIMEOUT")
    .unwrap_or_else(|_| "5".to_string())
    .parse()
    .unwrap_or(5);

    let url = format!("{}/cpf/{}", base_url, cpf_limpo);

    let client = Client::builder()
    .timeout(Duration::from_secs(timeout))
    .build()
    .map_err(|e| CpfError {
    message: format!("Erro ao criar cliente HTTP: {}", e),
    status_code: 500,
    })?;

    let response = client
    .get(&url)
    .header("x-api-key", &api_key)
    .header("Accept", "application/json")
    .send()
    .await
    .map_err(|e| {
    if e.is_timeout() {
    CpfError {
    message: "Timeout ao consultar a API".to_string(),
    status_code: 504,
    }
    } else {
    CpfError {
    message: format!("Erro de conexão: {}", e),
    status_code: 502,
    }
    }
    })?;

    let status = response.status().as_u16();

    match status {
    200 => {
    let body: CpfResponse = response.json().await.map_err(|e| CpfError {
    message: format!("Erro ao parsear resposta: {}", e),
    status_code: 500,
    })?;

    if body.success {
    body.data.ok_or(CpfError {
    message: "Resposta sem dados".to_string(),
    status_code: 500,
    })
    } else {
    Err(CpfError {
    message: "Consulta retornou sucesso falso".to_string(),
    status_code: 500,
    })
    }
    }
    400 => Err(CpfError { message: "CPF com formato inválido".to_string(), status_code: 400 }),
    401 => Err(CpfError { message: "Chave de API inválida".to_string(), status_code: 401 }),
    404 => Err(CpfError { message: "CPF não encontrado".to_string(), status_code: 404 }),
    _ => Err(CpfError { message: format!("Erro HTTP {}", status), status_code: status }),
    }
}

6. Registre o comando no main.rs

Registre o comando Tauri para que o frontend possa invocá-lo:

// src-tauri/src/main.rs
mod cpfhub;

use cpfhub::{CpfData, CpfError};

#[tauri::command]
async fn consultar_cpf_command(cpf: String) -> Result<CpfData, String> {
    dotenv::dotenv().ok();

    match cpfhub::consultar_cpf(&cpf).await {
    Ok(data) => Ok(data),
    Err(e) => Err(format!("{}: {}", e.status_code, e.message)),
    }
}

fn main() {
    tauri::Builder::default()
    .invoke_handler(tauri::generate_handler![consultar_cpf_command])
    .run(tauri::generate_context!())
    .expect("Erro ao iniciar aplicação Tauri");
}

7. Crie o frontend

No frontend, invoque o comando Rust via @tauri-apps/api:

<!-- src/index.html -->
<!DOCTYPE html>
<html lang="pt-BR">
<head>
    <meta charset="UTF-8">
    <title>Consulta de CPF - Tauri</title>
    <style>
    body { font-family: sans-serif; max-width: 600px; margin: 40px auto; padding: 0 20px; }
    input { padding: 10px; width: 200px; font-size: 16px; }
    button { padding: 10px 20px; font-size: 16px; cursor: pointer; }
    .resultado { margin-top: 20px; padding: 15px; border: 1px solid #ddd; border-radius: 4px; }
    .erro { color: #c0392b; }
    .sucesso { color: #27ae60; }
    </style>
</head>
<body>
    <h1>Consulta de CPF</h1>
    <div>
    <input type="text" id="cpf-input" placeholder="000.000.000-00" maxlength="14" />
    <button id="btn-consultar">Consultar</button>
    </div>
    <div id="resultado" class="resultado" style="display: none;"></div>
    <script type="module" src="/main.js"></script>
</body>
</html>
// src/main.js
const { invoke } = window.__TAURI__.core;

const btnConsultar = document.getElementById("btn-consultar");
const cpfInput = document.getElementById("cpf-input");
const resultadoDiv = document.getElementById("resultado");

btnConsultar.addEventListener("click", async () => {
    const cpf = cpfInput.value.trim();
    if (!cpf) {
    mostrarErro("Digite um CPF.");
    return;
    }

    resultadoDiv.style.display = "block";
    resultadoDiv.innerHTML = "Consultando...";
    resultadoDiv.className = "resultado";

    try {
    const dados = await invoke("consultar_cpf_command", { cpf });
    mostrarSucesso(dados);
    } catch (erro) {
    mostrarErro(erro);
    }
});

function mostrarSucesso(dados) {
    resultadoDiv.className = "resultado sucesso";
    resultadoDiv.innerHTML = `
    <h3>CPF Encontrado</h3>
    <p><strong>Nome:</strong> ${dados.name}</p>
    <p><strong>CPF:</strong> ${dados.cpf}</p>
    <p><strong>Genero:</strong> ${dados.gender}</p>
    <p><strong>Nascimento:</strong> ${dados.birth_date}</p>
    `;
}

function mostrarErro(mensagem) {
    resultadoDiv.className = "resultado erro";
    resultadoDiv.innerHTML = `<p>${mensagem}</p>`;
    resultadoDiv.style.display = "block";
}

8. Boas práticas

  • Segurança -- A chave de API fica exclusivamente no backend Rust, inacessível ao frontend. Nunca exponha credenciais no webview.

  • Timeout -- Configure timeout no reqwest::Client para evitar que a aplicação trave aguardando respostas da rede.

  • Variáveis de ambiente -- Use .env para desenvolvimento e variáveis de ambiente do sistema para distribuição.

  • Tratamento de erros -- Mapeie cada código HTTP para uma mensagem clara que será exibida ao usuário.

  • Performance -- O Tauri com Rust no backend oferece performance nativa. A API da CPFHub responde em ~900ms, proporcionando uma experiência fluida ao usuário.

  • LGPD -- A API da CPFHub.io é 100% compatível com a LGPD. Em aplicações desktop, garanta que dados pessoais não sejam armazenados localmente sem o consentimento do usuário.


Perguntas frequentes

Por que fazer a chamada à API de CPF pelo backend Rust no Tauri?

O backend Rust em uma aplicação Tauri roda em processo separado do webview, sem acesso via DevTools do navegador. Isso significa que a chave de API nunca fica exposta ao ambiente web — qualquer inspeção de tráfego ou acesso ao webview não revela a credencial. A prática segue as recomendações de segurança da OWASP para proteção de secrets em aplicações cliente.

A API da CPFHub.io bloqueia quando o limite do plano é atingido?

Não. Ao atingir o limite mensal, a API continua respondendo normalmente e cobra R$0,15 por consulta adicional — sem retornar erro nem bloquear requisições. O plano gratuito inclui 50 consultas/mês e o plano Pro inclui 1.000 consultas/mês por R$149. O controle de uso fica disponível no painel em app.cpfhub.io/settings/billing.

Como tratar o tempo de resposta de ~900ms em uma aplicação desktop Tauri?

Mostre um estado de carregamento no frontend assim que o usuário acionar a consulta, antes de aguardar a resposta do comando Rust. No frontend JavaScript, defina resultadoDiv.innerHTML = "Consultando..." antes do invoke, e use try/catch para exibir mensagem de erro em caso de timeout. Configure o reqwest::Client com timeout adequado para evitar que a UI trave indefinidamente.

Como distribuir uma aplicação Tauri com a chave de API protegida?

Para distribuição, use variáveis de ambiente do sistema operacional em vez de arquivo .env. O instalador pode solicitar a chave durante a configuração inicial e armazená-la nas variáveis de ambiente do usuário. Outra abordagem é usar um backend intermediário (seu próprio servidor) que armazena a chave e serve como proxy para a API da CPFHub.io, removendo completamente a credencial do pacote distribuído.



Conclusão

Integrar a API da CPFHub.io

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