# 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.

**Publicado:** 31/10/2024
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/como-validar-cpf-tempo-real-rust-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:

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

```rust
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,
}
```

| Camada | Operação | Custo |
|---|---|---|
| 1 - Formato | Verificar tamanho e caracteres | Negligível |
| 2 - Dígitos | Calcular dígitos verificadores | Negligível |
| 3 - API | Consultar base de dados externa | ~900ms |

---

## Implementando o validador completo

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

```rust
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:

```rust
#[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](https://doc.rust-lang.org/stable/book/ch17-00-async-await.html) 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](https://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.

### Leia também

- [Como consumir a API de CPF em Rust usando reqwest](https://cpfhub.io/blog/como-consumir-api-cpf-rust-reqwest)
- [Como processar consultas de CPF de forma assíncrona em Rust com Tokio](https://cpfhub.io/blog/como-processar-consultas-cpf-assincrono-rust-tokio)
- [SLA de API de CPF: níveis de disponibilidade e o que exigir do seu provedor](https://cpfhub.io/blog/sla-api-cpf-niveis-disponibilidade)
- [10 erros mais comuns ao integrar uma API de CPF e como evitá-los](https://cpfhub.io/blog/10-erros-mais-comuns-ao-integrar-uma-api-de-cpf)

---

## 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](https://www.cpfhub.io/) — 50 consultas mensais gratuitas, sem cartão de crédito — e comece a validar CPFs na sua aplicação Rust hoje mesmo.

