Como consumir a API de CPF em Rust usando reqwest

Aprenda a consumir a API de consulta de CPF em Rust usando a crate reqwest. Guia completo com exemplos práticos e tratamento de erros.

Redação CPFHub.io
Redação CPFHub.io
··6 min de leitura
Como consumir a API de CPF em Rust usando reqwest

Para consumir a API de CPF da CPFHub.io em Rust, use a crate reqwest com suporte a JSON e o runtime assíncrono tokio. A chamada é um GET https://api.cpfhub.io/cpf/{CPF} com o header x-api-key, e a resposta retorna nome, data de nascimento e gênero em cerca de 900ms. O serde cuida da desserialização para structs tipadas, tornando a integração segura e previsível.

Introdução

Rust é uma linguagem conhecida por sua segurança de memória e performance excepcional. A crate reqwest é a escolha mais popular para realizar requisições HTTP em Rust, oferecendo uma API ergonômica tanto síncrona quanto assíncrona. Este guia mostra como consumir a API da CPFHub.io usando reqwest com tipagem forte e tratamento robusto de erros.


Configurando o projeto Rust

Crie um novo projeto e adicione as dependências necessárias no Cargo.toml:

// Cargo.toml
[package]
name = "cpf-consulta"
version = "0.1.0"
edition = "2021"

[dependencies]
reqwest = { version = "0.12", features = ["json"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1", features = ["full"] }

A combinação de reqwest para HTTP, serde para serialização e tokio como runtime assíncrono forma a base de qualquer cliente HTTP em Rust.


Definindo as estruturas de dados

Utilize serde para mapear a resposta JSON da API em structs Rust com tipagem forte:

use serde::Deserialize;

#[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,
}
Campo na APICampo na StructTipo Rust
cpfcpfString
namenameString
nameUppername_upperString
gendergenderString
birthDatebirth_dateString
daydayString
monthmonthString
yearyearString

Realizando a consulta HTTP

Crie uma função assíncrona que realiza a consulta à API com os headers necessários:

use reqwest::header::{HeaderMap, HeaderValue};
use std::error::Error;

async fn consultar_cpf(cpf: &str, api_key: &str) -> Result<CpfResponse, Box<dyn Error>> {
    let mut headers = HeaderMap::new();
    headers.insert("x-api-key", HeaderValue::from_str(api_key)?);

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

    let response = client
    .get(&url)
    .headers(headers)
    .send()
    .await?
    .error_for_status()?;

    let cpf_response = response.json::<CpfResponse>().await?;
    Ok(cpf_response)
}

Tratamento de erros idiomático

Em Rust, o tratamento de erros é feito de forma explícita. Crie um tipo de erro customizado para lidar com os diferentes cenários de falha:

use std::fmt;

#[derive(Debug)]
pub enum CpfError {
    RequisicaoFalhou(reqwest::Error),
    CpfNaoEncontrado,
    ChaveInvalida,
    ErroDesconhecido(u16),
}

impl fmt::Display for CpfError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    match self {
    CpfError::RequisicaoFalhou(e) => write!(f, "Erro na requisição: {}", e),
    CpfError::CpfNaoEncontrado => write!(f, "CPF não encontrado na base"),
    CpfError::ChaveInvalida => write!(f, "Chave de API inválida"),
    CpfError::ErroDesconhecido(code) => write!(f, "Erro HTTP: {}", code),
    }
    }
}

impl std::error::Error for CpfError {}

async fn consultar_cpf_seguro(
    cpf: &str,
    api_key: &str,
) -> Result<CpfResponse, CpfError> {
    let mut headers = HeaderMap::new();
    headers.insert(
    "x-api-key",
    HeaderValue::from_str(api_key).map_err(|_| CpfError::ChaveInvalida)?,
    );

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

    let response = client
    .get(&url)
    .headers(headers)
    .send()
    .await
    .map_err(CpfError::RequisicaoFalhou)?;

    match response.status().as_u16() {
    200 => {
    let dados = response.json::<CpfResponse>().await
    .map_err(CpfError::RequisicaoFalhou)?;
    Ok(dados)
    }
    401 => Err(CpfError::ChaveInvalida),
    404 => Err(CpfError::CpfNaoEncontrado),
    // Nota: a CPFHub.io não retorna 429; ao superar a cota, cobra R$0,15/consulta extra
    code => Err(CpfError::ErroDesconhecido(code)),
    }
}

Exemplo completo com Tokio

Monte o programa principal utilizando o runtime tokio:

#[tokio::main]
async fn main() {
    let api_key = "SUA_API_KEY";
    let cpf = "12345678900";

    match consultar_cpf_seguro(cpf, api_key).await {
    Ok(resultado) => {
    println!("CPF encontrado com sucesso!");
    println!(" Nome: {}", resultado.data.name);
    println!(" CPF: {}", resultado.data.cpf);
    println!(" Nascimento: {}", resultado.data.birth_date);
    println!(" Gênero: {}", resultado.data.gender);
    }
    Err(CpfError::CpfNaoEncontrado) => {
    println!("O CPF informado não foi encontrado.");
    }
    Err(CpfError::ChaveInvalida) => {
    println!("Chave de API inválida. Verifique suas credenciais.");
    }
    Err(e) => {
    eprintln!("Erro inesperado: {}", e);
    }
    }
}

Perguntas frequentes

A CPFHub.io retorna erro 429 quando o limite de consultas é atingido?

Não. A API da CPFHub.io nunca retorna HTTP 429 nem bloqueia requisições. Ao superar a cota mensal (50 no plano gratuito, 1.000 no plano Pro), cada consulta adicional é cobrada automaticamente a R$0,15 — o serviço continua respondendo normalmente. Por isso, o tratamento de erro no código Rust não precisa contemplar esse status.

Como desserializar corretamente o JSON da CPFHub.io em Rust com serde?

Use #[serde(rename_all = "camelCase")] na struct de dados para mapear campos como nameUpper e birthDate automaticamente para name_upper e birth_date. O campo success fica na struct raiz e data é uma struct aninhada. Consulte a documentação do serde para padrões avançados de desserialização.

Qual é o tempo de resposta típico da API ao fazer requisições com reqwest?

A CPFHub.io responde em aproximadamente 900ms. Configure o timeout do cliente reqwest para pelo menos 10 segundos para evitar interrupções em condições normais de rede. Use .timeout(std::time::Duration::from_secs(10)) no builder do cliente.

Como organizar o cliente HTTP em uma aplicação maior em Rust?

Crie um struct CpfClient que encapsula o reqwest::Client e a API key, então registre-o como dado compartilhado (por exemplo, Arc<CpfClient>) entre as tarefas assíncronas. Isso evita criar um novo cliente a cada requisição e garante reutilização do pool de conexões TCP.


Conclusão

Consumir a API de CPF em Rust com reqwest resulta em código performático, seguro e com tratamento de erros explícito. A tipagem forte do Rust, combinada com serde para desserialização, garante que os dados da API sejam manipulados de forma confiável. Cadastre-se em cpfhub.io — 50 consultas mensais gratuitas, sem cartão de crédito — e comece a integrar consultas de CPF em sua aplicação Rust 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