rbytes_consulta_cep 0.1.0

Consulta de CEP brasileiro com multi-provedores (ViaCEP, BrasilAPI, etc). Inclui fallback automático, timeout configurável e formatação de endereços.
Documentation
// src/providers/viacep.rs
use crate::{models::Endereco, error::CepError, validacao::normalizar_cep};
use reqwest::{Client, StatusCode}; // Adicione StatusCode aqui
use serde::Deserialize;
use std::time::Duration;
use serde_json::Value;

#[derive(Debug, Deserialize)]
struct ViaCepResponse {
    cep: String,
    logradouro: String,
    complemento: String,
    bairro: String,
    localidade: String,
    uf: String,
    ibge: Option<String>,
    gia: Option<String>,
    ddd: Option<String>,
    siafi: Option<String>,
    #[serde(default)]
    erro: bool,
}

pub async fn consultar(cep: &str) -> Result<Endereco, CepError> {
    let cep_normalizado = normalizar_cep(cep)?;
    let url = format!("https://viacep.com.br/ws/{}/json/", cep_normalizado);
    
    let response = Client::new()
        .get(&url)
        .timeout(Duration::from_secs(2))
        .send()
        .await?;

    match response.status() {
        StatusCode::OK => {
            let viacep_response: ViaCepResponse = response.json().await?;
            
            if viacep_response.erro {
                return Err(CepError::CepNaoEncontrado);
            }

            Ok(Endereco {
                cep: viacep_response.cep,
                logradouro: Some(viacep_response.logradouro)
                    .filter(|s| !s.is_empty()),
                complemento: Some(viacep_response.complemento)
                    .filter(|s| !s.is_empty()),
                bairro: Some(viacep_response.bairro)
                    .filter(|s| !s.is_empty()),
                localidade: viacep_response.localidade,
                uf: viacep_response.uf,
                ibge: viacep_response.ibge,
                gia: viacep_response.gia,
                ddd: viacep_response.ddd,
                siafi: viacep_response.siafi,
            })
        },
        StatusCode::BAD_REQUEST => Err(CepError::CepInvalido),
        StatusCode::TOO_MANY_REQUESTS => Err(CepError::RateLimitExcedido("ViaCEP".into())),
        _ => Err(CepError::ProvedorIndisponivel("ViaCEP".into())),
    }
}