use crate::{
error::CepError,
models::Endereco,
validacao::{normalizar_cep, formatar_cep} };
use reqwest::{Client, StatusCode};
use serde::Deserialize;
use std::time::Duration;
#[derive(Debug, Deserialize)]
struct ApiCepResponse {
code: String,
state: String,
city: String,
district: String,
address: String,
status: u32,
ok: bool,
statusText: String,
}
pub async fn consultar(cep: &str) -> Result<Endereco, CepError> {
let cep_formatado = formatar_cep(cep)?;
let url = format!("https://cdn.apicep.com/file/apicep/{}.json", cep_formatado);
let response = Client::new()
.get(&url)
.timeout(Duration::from_secs(2))
.send()
.await?;
match response.status() {
StatusCode::OK => {
let apicep_response: ApiCepResponse = response.json().await?;
if !apicep_response.ok {
return Err(CepError::CepNaoEncontrado);
}
Ok(Endereco {
cep: apicep_response.code,
logradouro: Some(apicep_response.address)
.filter(|s| !s.is_empty()),
complemento: None,
bairro: Some(apicep_response.district)
.filter(|s| !s.is_empty()),
localidade: apicep_response.city,
uf: apicep_response.state,
ibge: None,
gia: None,
ddd: None,
siafi: None,
})
},
StatusCode::BAD_REQUEST => Err(CepError::CepInvalido),
StatusCode::TOO_MANY_REQUESTS => Err(CepError::RateLimitExcedido("ApiCEP".into())),
_ => Err(CepError::ProvedorIndisponivel("ApiCEP".into())),
}
}