100-days-of-rust/Week-03/Day-20_API-Challenge/day20/src/lib.rs

57 lines
1.8 KiB
Rust

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<Response, reqwest::Error> {
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<String>,
latitude: Option<f32>,
longitude: Option<f32>,
}
pub async fn search_handler(Query(params): Query<Params>) -> Json<Value> {
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<HashMap<String, Value>> = 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 }))
}