Como validar CPF em tempo real usando Rust e APIs REST

Aprenda a validar CPF em tempo real em Rust combinando validação algorítmica local com consulta à API REST do CPFHub.

Redação CPFHub.io
Redação CPFHub.io
··6 min de leitura
Como validar CPF em tempo real usando Rust e APIs REST

Validar CPF em tempo real com Rust combina verificação algorítmica dos dígitos verificadores — feita localmente, sem custo de rede — com uma consulta à API REST da CPFHub.io que retorna nome completo, gênero e data de nascimento em ~900ms. O sistema de tipos de Rust garante que todos os cenários de erro sejam tratados em tempo de compilação, resultando em integrações robustas e sem surpresas em produção. A API nunca retorna HTTP 429 ao ultrapassar o limite: consultas adicionais são cobradas a R$0,15 cada.

Introdução

Validar um CPF vai além de verificar seus dígitos verificadores. A validação em tempo real combina a checagem algorítmica local com a confirmação dos dados através de uma API externa. Rust, com seu sistema de tipos e performance, é uma escolha excelente para implementar esse tipo de validação.


Validação algorítmica do CPF

O CPF brasileiro possui dois dígitos verificadores calculados a partir dos nove primeiros dígitos. Implemente essa validação de forma idiomática em Rust:

pub fn validar_digitos_cpf(cpf: &str) -> bool {
    let digitos: Vec<u32> = cpf.chars()
    .filter(|c| c.is_ascii_digit())
    .filter_map(|c| c.to_digit(10))
    .collect();

    if digitos.len() != 11 {
    return false;
    }

    // Rejeitar CPFs com todos os dígitos iguais
    if digitos.iter().all(|&d| d == digitos[0]) {
    return false;
    }

    // Primeiro dígito verificador
    let soma: u32 = digitos.iter()
    .take(9)
    .enumerate()
    .map(|(i, &d)| d * (10 - i as u32))
    .sum();
    let d1 = if soma % 11 < 2 { 0 } else { 11 - (soma % 11) };

    // Segundo dígito verificador
    let soma: u32 = digitos.iter()
    .take(10)
    .enumerate()
    .map(|(i, &d)| d * (11 - i as u32))
    .sum();
    let d2 = if soma % 11 < 2 { 0 } else { 11 - (soma % 11) };

    digitos[9] == d1 && digitos[10] == d2
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_cpf_invalido_digitos_iguais() {
    assert!(!validar_digitos_cpf("11111111111"));
    }

    #[test]
    fn test_cpf_invalido_tamanho() {
    assert!(!validar_digitos_cpf("1234"));
    }
}

Estrutura de validação em camadas

Organize a validação em etapas progressivas para otimizar o uso de recursos:

use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize)]
pub struct ValidacaoResult {
    pub formato_valido: bool,
    pub encontrado_na_base: bool,
    pub nome: Option<String>,
    pub data_nascimento: Option<String>,
    pub mensagem: String,
}

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

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct CpfData {
    pub cpf: String,
    pub name: String,
    pub name_upper: String,
    pub gender: String,
    pub birth_date: String,
    pub day: String,
    pub month: String,
    pub year: String,
}
CamadaOperaçãoCusto
1 - FormatoVerificar tamanho e caracteresNegligível
2 - DígitosCalcular dígitos verificadoresNegligível
3 - APIConsultar base de dados externa~900ms

Implementando o validador completo

Combine todas as camadas em uma função assíncrona que retorna o resultado detalhado:

use reqwest::header::{HeaderMap, HeaderValue};

pub struct CpfValidator {
    client: reqwest::Client,
    api_key: String,
}

impl CpfValidator {
    pub fn new(api_key: String) -> Self {
    let client = reqwest::Client::builder()
    .timeout(std::time::Duration::from_secs(5))
    .build()
    .expect("Falha ao criar cliente HTTP");

    Self { client, api_key }
    }

    pub async fn validar_completo(&self, cpf: &str) -> ValidacaoResult {
    let cpf_limpo: String = cpf.chars()
    .filter(|c| c.is_ascii_digit())
    .collect();

    // Camada 1: Formato
    if cpf_limpo.len() != 11 {
    return ValidacaoResult {
    formato_valido: false,
    encontrado_na_base: false,
    nome: None,
    data_nascimento: None,
    mensagem: "CPF deve conter 11 dígitos".to_string(),
    };
    }

    // Camada 2: Dígitos verificadores
    if !validar_digitos_cpf(&cpf_limpo) {
    return ValidacaoResult {
    formato_valido: false,
    encontrado_na_base: false,
    nome: None,
    data_nascimento: None,
    mensagem: "Dígitos verificadores inválidos".to_string(),
    };
    }

    // Camada 3: Consulta à API
    match self.consultar_api(&cpf_limpo).await {
    Ok(response) if response.success => ValidacaoResult {
    formato_valido: true,
    encontrado_na_base: true,
    nome: Some(response.data.name),
    data_nascimento: Some(response.data.birth_date),
    mensagem: "CPF válido e encontrado na base".to_string(),
    },
    Ok(_) => ValidacaoResult {
    formato_valido: true,
    encontrado_na_base: false,
    nome: None,
    data_nascimento: None,
    mensagem: "CPF válido, porém não encontrado".to_string(),
    },
    Err(e) => ValidacaoResult {
    formato_valido: true,
    encontrado_na_base: false,
    nome: None,
    data_nascimento: None,
    mensagem: format!("Erro ao consultar API: {}", e),
    },
    }
    }

    async fn consultar_api(&self, cpf: &str) -> Result<CpfResponse, String> {
    let mut headers = HeaderMap::new();
    headers.insert(
    "x-api-key",
    HeaderValue::from_str(&self.api_key)
    .map_err(|e| e.to_string())?,
    );

    let url = format!("https://api.cpfhub.io/cpf/{}", cpf);

    let response = self.client
    .get(&url)
    .headers(headers)
    .send()
    .await
    .map_err(|e| e.to_string())?;

    response.json::<CpfResponse>()
    .await
    .map_err(|e| e.to_string())
    }
}

Utilizando o validador

Integre o validador no seu programa principal:

#[tokio::main]
async fn main() {
    let api_key = std::env::var("CPFHUB_API_KEY")
    .expect("Defina CPFHUB_API_KEY no ambiente");

    let validator = CpfValidator::new(api_key);

    let cpfs = vec!["12345678900", "11111111111", "98765432100"];

    for cpf in cpfs {
    let resultado = validator.validar_completo(cpf).await;
    println!("CPF: {} -> {}", cpf, resultado.mensagem);

    if let Some(nome) = &resultado.nome {
    println!(" Nome: {}", nome);
    }
    if let Some(nascimento) = &resultado.data_nascimento {
    println!(" Nascimento: {}", nascimento);
    }
    println!("---");
    }
}

Para referência sobre o modelo assíncrono de Rust, consulte a documentação oficial do Tokio e a crate reqwest.


Perguntas frequentes

O que acontece quando o volume de consultas ultrapassa o limite do plano em Rust?

A API da CPFHub.io nunca retorna HTTP 429 nem interrompe requisições. Quando o limite mensal é superado, cada consulta adicional é cobrada a R$0,15. Isso significa que seu código Rust não precisa implementar lógica de retry por bloqueio de quota — o fluxo continua normalmente, e você acompanha o consumo em app.cpfhub.io/settings/billing.

Por que usar validação em camadas em vez de consultar a API diretamente?

A camada algorítmica local (formato e dígitos verificadores) rejeita CPFs matematicamente inválidos sem nenhuma chamada de rede, reduzindo custos e latência. Apenas CPFs com dígitos válidos chegam à camada 3 (API), que confirma existência e retorna os dados cadastrais.

Como tratar erros de timeout na consulta à API em Rust?

Configure o reqwest::Client com .timeout(Duration::from_secs(5)) como mostrado no exemplo. O tipo Result<CpfResponse, String> garante que erros de rede sejam tratados explicitamente — o compilador de Rust não deixa ignorar o caso de erro, o que torna a integração mais robusta.

Qual crate usar para deserializar a resposta JSON da CPFHub.io em Rust?

Use serde com serde_json (ou o suporte JSON integrado do reqwest via feature json). Os campos da resposta seguem camelCase — use #[serde(rename_all = "camelCase")] na struct CpfData para mapear automaticamente birthDate, nameUpper etc., como demonstrado neste artigo.


Conclusão

A validação de CPF em tempo real com Rust combina a eficiência da verificação algorítmica local com a riqueza de dados da API da CPFHub.io. O sistema de tipos de Rust garante que todos os cenários de erro sejam tratados explicitamente, resultando em software robusto e confiável. A API responde em ~900ms e nunca bloqueia por volume — consultas além do plano são simplesmente cobradas como excedente.

Cadastre-se em cpfhub.io — 50 consultas mensais gratuitas, sem cartão de crédito — e comece a validar CPFs na sua aplicação Rust hoje mesmo.

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