fetch_tours.rs en Rust
Un CLI real: clap parsea los flags, reqwest descarga, serde modela la respuesta.
use std::error::Error;
use std::time::Duration;
use clap::Parser;
use serde::Deserialize;
/// Fetch the tour list for a language.
#[derive(Parser, Debug)]
#[command(name = "fetch-tours", version)]
struct Cli {
/// Language slug, such as rust or sql
lang: String,
/// Base URL of the server
#[arg(long, default_value = "https://typestar.io")]
base: String,
/// Only show tours with at least this many steps
#[arg(long, default_value_t = 0)]
min_steps: usize,
/// Print the raw JSON as well
#[arg(short, long)]
verbose: bool,
}
#[derive(Debug, Deserialize)]
struct Paths {
lang: String,
tours: Vec<Tour>,
}
#[derive(Debug, Deserialize)]
struct Tour {
slug: String,
title: String,
sections: Vec<Section>,
}
#[derive(Debug, Deserialize)]
struct Section {
title: String,
steps: Vec<Step>,
}
#[derive(Debug, Deserialize)]
struct Step {
idx: u32,
title: String,
}
impl Tour {
fn step_count(&self) -> usize {
self.sections.iter().map(|s| s.steps.len()).sum()
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let cli = Cli::parse();
let client = reqwest::Client::builder()
.timeout(Duration::from_secs(15))
.user_agent("fetch-tours/1.0")
.build()?;
let url = format!("{}/api/paths?lang={}", cli.base, cli.lang);
let response = client.get(&url).send().await?.error_for_status()?;
let body = response.text().await?;
if cli.verbose {
println!("{} bytes from {url}", body.len());
}
let paths: Paths = serde_json::from_str(&body)?;
println!("{} has {} tours", paths.lang, paths.tours.len());
for tour in paths.tours.iter().filter(|t| t.step_count() >= cli.min_steps) {
println!("{:<12} {:<32} {:>3} steps", tour.slug, tour.title,
tour.step_count());
if cli.verbose {
for section in &tour.sections {
println!(" {} ({})", section.title, section.steps.len());
}
}
}
let widest = paths.tours.iter().max_by_key(|t| t.step_count());
if let Some(tour) = widest {
println!("largest tour: {}", tour.title);
}
Ok(())
}
Cómo funciona
- El struct
Clies toda la interfaz, texto de ayuda incluido. - Los modelos espejan la respuesta de la API que la herramienta consume.
- Los errores de tres crates desembocan todos en
Box<dyn Error>.
Palabras clave y builtins usados aquí
BoxOkResultSomeStringVecasyncawaitbooldynfnforifimplinletselfstructu32useusize
El intento, en números
- Líneas
- 93
- Caracteres a escribir
- 1932
- Tokens
- 486
- Ritmo de tres estrellas
- 115 tpm
Al ritmo de tres estrellas de 115 tokens por minuto, este intento toma unos 254 segundos.
Paso 1 de 1 en Bis; paso 12 de 12 en Herramientas CLI y clientes HTTP.