#![deny(warnings)] #![warn(rust_2018_idioms)] use bytes::Bytes; use http_body_util::{BodyExt, Empty}; use hyper::{body::Buf, Request}; use serde::Deserialize; use tokio::net::TcpStream; #[path = "../benches/support/mod.rs"] mod support; use support::TokioIo; // A simple type alias so as to DRY. type Result = std::result::Result>; #[tokio::main] async fn main() -> Result<()> { let url = "http://jsonplaceholder.typicode.com/users".parse().unwrap(); let users = fetch_json(url).await?; // print users println!("users: {:#?}", users); // print the sum of ids let sum = users.iter().fold(0, |acc, user| acc + user.id); println!("sum of ids: {}", sum); Ok(()) } async fn fetch_json(url: hyper::Uri) -> Result> { let host = url.host().expect("uri has no host"); let port = url.port_u16().unwrap_or(80); let addr = format!("{}:{}", host, port); let stream = TcpStream::connect(addr).await?; let io = TokioIo::new(stream); let (mut sender, conn) = hyper::client::conn::http1::handshake(io).await?; tokio::task::spawn(async move { if let Err(err) = conn.await { println!("Connection failed: {:?}", err); } }); let authority = url.authority().unwrap().clone(); // Fetch the url... let req = Request::builder() .uri(url) .header(hyper::header::HOST, authority.as_str()) .body(Empty::::new())?; let res = sender.send_request(req).await?; // asynchronously aggregate the chunks of the body let body = res.collect().await?.aggregate(); // try to parse as json with serde_json let users = serde_json::from_reader(body.reader())?; Ok(users) } #[derive(Deserialize, Debug)] struct User { id: i32, #[allow(unused)] name: String, }