reqwest
Instalación
- El cliente asíncrono
async(sin flag; por defecto) requiere Tokio pero para para aplicaciones o scripts que realizan pocas solicitudes es más conveniente usar con la flagblocking jsonpara deserealizar la respuesta directamente a JSONdefault-tlspor defecto, pero se puede usarrustls
cargo add reqwest -F blocking,json,rustls
Ejemplos
El código para usar reqwest es bastante pequeño, pero los ejemplos son para demostrar un uso normal, incluyendo la manipulación de resultado y no solo las llamadas HTTP
Get
- No es necesario crear un cliente porque ya expone un helper
::getpero si es para varias solicitudes entonces es mejor crear el cliente.
let body: Vec<Product> = reqwest::blocking::get("https://www.junlaj.com/api/units/1")?.json()?;
println!("{body:#?}");
#[derive(Serialize, Deserialize, Debug)]
struct Unit {
id: i32,
name: String,
image: Option<String>,
}
let body = reqwest::get("https://example.com")
.await?
.text()
.await?;
println!("{body:?}");
Post Json
- Es necesario crear un cliente ya sea
async(por defecto) oblocking - Dependiendo los headers que solicite la API se pueden escribir manualmente ya sea de una en una o como array, pero hay headers que son bastante comunes como
Bearerque ya tiene un helper - Si se envía un JSON, entonces también es necesario agregar el header, pero también expone un método
json()que toma el body y agrega en automático el header
// Por defecto son 30 segundos de TimeOut
let client = reqwest::blocking::Client::new();
// Algunas solicitudes, como a LLMs pueden tomar más de 30 segundos
let client = reqwest::blocking::Client::builder()
.timeout(Duration::from_secs(600))
.build()?;
// Construir el body usando serde
let body = serde_json::json!({
"prompt": "Crea un perro. Estilo cartoon. Sin fondo",
"model": "gpt-image-2.5-flare",
"size": "1024x1024",
"n": 1,
"output_format": "png",
"background": "transparent",
"quality": "high"
});
// Respuesta
let response = client.post(&url).bearer_auth(&api_key).json(&body).send()?;
// Validar estatus de la respuesta
if !response.status().is_success() {
let status = response.status();
let body: serde_json::Value = response.json()?;
eprintln!("Error: {status} - {body}");
return Err(format!("Error: {status} - {body}").into());
}
// Procesar respuesta
// ...
Respuesta Json y/o base64
// ...
// La respuesta por defecto es .text,
// Si se desea serealizar directamente a JSON,
// entonces requiere la flag json
let response: serde_json::Value = response.json()?;
// ".ok_or" lanza el error con el contenido del response
let base64_data = response["data"][0]["b64_json"]
.as_str()
.ok_or(response.to_string())?;
// Decodificando con el crate base64
let decode = base64::engine::general_purpose::STANDARD.decode(base64_data)?;
// Guardar el archivo
// "write" es una función de conveniencia para "File::create" + "write_all"
std::fs::write("resources/images/file_name.png", decode)?;
Respuesta directamente en bytes
- Por ejemplo, APIs que responden directamente los bytes del audio
// ...
// Crear el contendio o bytes
let audio_bytes = response.bytes()?;
// Guardar el archivo
std::fs::write("resources/audio/test.opus", audio_bytes)?;