diff --git a/README.md b/README.md index 0c190c4..801a338 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ We encourage you to share your progress and ask questions in the Discussions sec | Day #17 | [Prison Break](https://github.com/LiveGray/100-Days-Of-Rust/tree/main/Week-03/Day-17_Prison-Break) | :white_check_mark: | | Day #18 | [Unique Paths](https://github.com/LiveGray/100-Days-Of-Rust/tree/main/Week-03/Day-18_Unique-Paths) | :white_check_mark: | | Day #19 | [URL Shortener](https://github.com/LiveGray/100-Days-Of-Rust/tree/main/Week-03/Day-19_URL-Shortener) | :white_check_mark: | -| Day #20 | [API Challenge](https://github.com/LiveGray/100-Days-Of-Rust/tree/main/Week-03/Day-20_API-Challenge) | :white_large_square: | +| Day #20 | [API Challenge](https://github.com/LiveGray/100-Days-Of-Rust/tree/main/Week-03/Day-20_API-Challenge) | :white_check_mark: | | Day #21 | [Random Maze Generator](https://github.com/LiveGray/100-Days-Of-Rust/tree/main/Week-03/Day-21_Random-Maze-Generator) | :white_large_square: | | Day #22 | [Marcio Mellos Challenge](https://github.com/LiveGray/100-Days-Of-Rust/tree/main/Week-04/Day-22_Marcio-Mellos-Challenge) | :white_large_square: | | Day #23 | [The Dining Philosophers](https://github.com/LiveGray/100-Days-Of-Rust/tree/main/Week-04/Day-23_The-Dining_Philosophers) | :white_large_square: | diff --git a/Week-03/Day-20_API-Challenge/day20/Cargo.toml b/Week-03/Day-20_API-Challenge/day20/Cargo.toml new file mode 100644 index 0000000..42c9777 --- /dev/null +++ b/Week-03/Day-20_API-Challenge/day20/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "day20" +version = "0.1.0" +edition = "2021" + +[dependencies] +axum = "0.7.5" +reqwest = "0.12.5" +serde = { version = "1.0.207", features = ["derive"] } +serde_json = "1.0.124" +tokio = { version = "1.39.2", features = ["full"] } diff --git a/Week-03/Day-20_API-Challenge/day20/src/lib.rs b/Week-03/Day-20_API-Challenge/day20/src/lib.rs new file mode 100644 index 0000000..63a3701 --- /dev/null +++ b/Week-03/Day-20_API-Challenge/day20/src/lib.rs @@ -0,0 +1,56 @@ +use axum::{extract::Query, Json}; +use reqwest::Response; +use serde::Deserialize; +use serde_json::{from_str, json, Value}; +use std::collections::HashMap; + +pub async fn search(params: Params) -> Result { + let client = reqwest::Client::builder() + .user_agent("JustLearningRust/1.0") + .build()?; + + let mut query = String::new(); + + if let Some(q) = params.q { + query.push_str(&format!("&q={}", q)); + } + if let Some(latitude) = params.latitude { + query.push_str(&format!("&lat={}", latitude)); + } + if let Some(longitude) = params.longitude { + query.push_str(&format!("&lon={}", longitude)); + } + + let url = format!( + "https://nominatim.openstreetmap.org/search?format=json{}", + query + ); + let res = client.get(url).send().await?; + + Ok(res) +} + +#[derive(Deserialize)] +pub struct Params { + q: Option, + latitude: Option, + longitude: Option, +} + +pub async fn search_handler(Query(params): Query) -> Json { + let res = search(params).await.expect("Failed to get response body"); + let str = &res.text().await.expect("Failed to get response body"); + let json: Vec> = from_str(str).unwrap(); + let mut ret = Vec::new(); + for el in json.iter() { + let display_name = el.get("display_name").unwrap().as_str().unwrap(); + if display_name.contains("United States") + || display_name.contains("Canada") + || display_name.contains("Brasil") + // there's no way to filter by population + { + ret.push(json!({"name": el.get("display_name"), "latitude": el.get("lat"), "longitude": el.get("lon"), "score": el.get("importance")})); + } + } + Json(json!({ "suggestions": ret })) +} diff --git a/Week-03/Day-20_API-Challenge/day20/src/main.rs b/Week-03/Day-20_API-Challenge/day20/src/main.rs new file mode 100644 index 0000000..3b66962 --- /dev/null +++ b/Week-03/Day-20_API-Challenge/day20/src/main.rs @@ -0,0 +1,11 @@ +use axum::routing::{get, Router}; +use day20::search_handler; + +#[tokio::main] +async fn main() { + let app = Router::new().route("/suggestions", get(search_handler)); + let listener = tokio::net::TcpListener::bind(&"0.0.0.0:3000") + .await + .unwrap(); + axum::serve(listener, app).await.unwrap(); +}