use std::io::Cursor; use std::str::FromStr; use tiny_http::{Header, Response}; use crate::repo::ingredient::StaticIngredientRepo; use crate::rest::types::{QueryParams, Url}; use crate::{domain, rest}; #[derive(Default, Debug)] struct FetchIngredientsOpts<'a> { keys: Option>, } impl<'a> From<&QueryParams<'a>> for FetchIngredientsOpts<'a> { fn from(params: &QueryParams<'a>) -> Self { params .iter() .fold(FetchIngredientsOpts::default(), |mut opts, p| { match p { ("key", val) => { let mut keys = opts.keys.unwrap_or_default(); keys.push(val); opts.keys = Some(keys) } _ => {} }; opts }) } } impl From> for domain::ingredient::fetch_list::RequestOpts { fn from(rest: FetchIngredientsOpts) -> Self { let keys = rest .keys .map(|keys| keys.into_iter().map(String::from).collect()); Self { keys } } } pub fn fetch_list(rest_ctx: &rest::Context, url: &Url) -> Response>> { use domain::ingredient::fetch_list; let opts = FetchIngredientsOpts::from(url.query_params()); let ctx = rest_ctx.clone().into(); let repo = StaticIngredientRepo; let ingredients = fetch_list::execute(&repo, &ctx, opts.into()) .into_iter() .map(rest::Ingredient::from) .collect::>(); let data = serde_json::to_string(&ingredients).unwrap(); Response::from_string(data) .with_header(Header::from_str("content-type: application/json").unwrap()) } pub fn fetch_by_key(rest_ctx: &rest::Context, _url: &Url, key: &str) -> Response>> { use domain::ingredient::fetch_by_key; let repo = StaticIngredientRepo; let ctx = rest_ctx.clone().into(); // TODO: catch notfound error let ingredient = fetch_by_key::execute(&repo, &ctx, key.to_string()) .ok() .map(rest::Ingredient::from); let data = serde_json::to_string(&ingredient).unwrap(); Response::from_string(data) .with_header(Header::from_str("content-type: application/json").unwrap()) }