// During development, allowing dead code #![allow(dead_code)] use async_recursion::async_recursion; use clap::Parser; use std::fmt::Write; use std::error::Error; // use std::time::Duration; // use std::thread::sleep; use serde::Deserialize; type DataResult = Result>; const BASE_URL: &str = "https://api.semanticscholar.org/graph/v1"; const MAX_DEPTH: u32 = 3; #[derive(Parser, Debug)] #[clap(author, version, about, long_about = None)] struct Args { /// URL to query #[clap(short, long, value_parser)] paper_id: String, } struct Author { name: String } struct Paper { authors: Vec } /** * Occurs within Citation struct */ #[derive(Deserialize, Debug)] #[serde(rename_all = "camelCase")] struct CitingPaper { paper_id: String, title: String, } #[derive(Deserialize, Debug)] #[serde(rename_all = "camelCase")] struct Citation { citing_paper: CitingPaper } /** * Generic struct to wrap the common API response pattern {data: [...]} */ #[derive(Deserialize, Debug)] struct ApiListResponse { data: Vec } // TODO: Cache results in a (separate but local) database such as Redis // TODO: Store results in a (separate but local) database such as Postgres #[async_recursion] async fn get_citations(paper_id: String, depth: u32) -> DataResult> { // Bound recursion to some depth if depth > MAX_DEPTH { return Ok(vec![]); } // Naieve approach to possible rate-limiting // sleep(Duration::new(1, 0)); // Build the URL let mut url = String::new(); write!(&mut url, "{}/paper/{}/citations", BASE_URL, paper_id)?; let resp = reqwest::get(url) .await? .text() .await?; // .json::().await?; let resp_deserialized_attempt = serde_json::from_str::>(resp.as_str()); if let Err(err) = resp_deserialized_attempt { println!("depth {} paper {} error {}", depth, paper_id, err); return Ok(vec![]); } let resp_deserialized: ApiListResponse = resp_deserialized_attempt.unwrap(); for Citation{citing_paper: CitingPaper{paper_id: cited_id, title}} in resp_deserialized.data { println!("depth {} paper {} cites {} title {}", depth, paper_id, cited_id, title); get_citations(cited_id, depth + 1).await?; } Ok(vec![]) } #[tokio::main] async fn main() -> Result<(), Box> { let Args{ paper_id } = Args::parse(); // let mut authors: Vec = Vec::new(); // let citations = get_citations(paper_id, 0).await?; Ok(()) }