diff --git a/app/src/api.rs b/app/src/api.rs index 894d1e2..dd9c618 100644 --- a/app/src/api.rs +++ b/app/src/api.rs @@ -39,103 +39,138 @@ where }) } +struct RequestBody(T); + +impl<'a, R> From<&'a R> for RequestBody> +where + R: serde::ser::Serialize, +{ + fn from(request: &'a R) -> Self { + Self(Json(&request)) + } +} + +impl From for RequestBody { + fn from(request: yew::format::Nothing) -> Self { + Self(request) + } +} + +fn call_server( + url: &str, + request: RB, + callback: Callback>, + handler: F, +) -> Result +where + F: Fn(http::StatusCode, Resp) -> Result + 'static, + CallbackResult: 'static, + RB: Into>, + Req: Into, + Result: From> + 'static, +{ + let request = Request::post(url) + .header("Content-Type", "application/json") + .body(request.into().0)?; + let handler = create_handler(callback, handler); + FetchService::fetch_with_options(request, get_default_options(), handler) +} + impl HostService { pub fn list_users( request: ListUsersRequest, callback: Callback>>, ) -> Result { - let url = "/api/users"; - let request = Request::post(url) - .header("Content-Type", "application/json") - .body(Json(&request))?; - let handler = create_handler(callback, |status, data: String| { + call_server("/api/users", &request, callback, |status, data: String| { if status.is_success() { serde_json::from_str(&data).map_err(|e| anyhow!("Could not parse response: {}", e)) } else { Err(anyhow!("[{}]: {}", status, data)) } - }); - FetchService::fetch_with_options(request, get_default_options(), handler) + }) } pub fn login_start( request: login::ClientLoginStartRequest, callback: Callback>, ) -> Result { - let url = "/auth/opaque/login/start"; - let request = Request::post(url) - .header("Content-Type", "application/json") - .body(Json(&request))?; - let handler = create_handler(callback, |status, data: String| { - if status.is_success() { - serde_json::from_str(&data).map_err(|e| anyhow!("Could not parse response: {}", e)) - } else { - Err(anyhow!( - "Could not start authentication: [{}]: {}", - status, - data - )) - } - }); - FetchService::fetch_with_options(request, get_default_options(), handler) + call_server( + "/auth/opaque/login/start", + &request, + callback, + |status, data: String| { + if status.is_success() { + serde_json::from_str(&data) + .map_err(|e| anyhow!("Could not parse response: {}", e)) + } else { + Err(anyhow!( + "Could not start authentication: [{}]: {}", + status, + data + )) + } + }, + ) } pub fn login_finish( request: login::ClientLoginFinishRequest, callback: Callback>, ) -> Result { - let url = "/auth/opaque/login/finish"; - let request = Request::post(url) - .header("Content-Type", "application/json") - .body(Json(&request))?; - let handler = create_handler(callback, |status, data: String| { - if status.is_success() { - get_claims_from_jwt(&data) - .map_err(|e| anyhow!("Could not parse response: {}", e)) - .and_then(|jwt_claims| { - set_cookie("user_id", &jwt_claims.user, &jwt_claims.exp) - .map(|_| jwt_claims.user.clone()) - .map_err(|e| anyhow!("Error clearing cookie: {}", e)) - }) - } else { - Err(anyhow!( - "Could not finish authentication: [{}]: {}", - status, - data - )) - } - }); - FetchService::fetch_with_options(request, get_default_options(), handler) + call_server( + "/auth/opaque/login/finish", + &request, + callback, + |status, data: String| { + if status.is_success() { + get_claims_from_jwt(&data) + .map_err(|e| anyhow!("Could not parse response: {}", e)) + .and_then(|jwt_claims| { + set_cookie("user_id", &jwt_claims.user, &jwt_claims.exp) + .map(|_| jwt_claims.user.clone()) + .map_err(|e| anyhow!("Error clearing cookie: {}", e)) + }) + } else { + Err(anyhow!( + "Could not finish authentication: [{}]: {}", + status, + data + )) + } + }, + ) } pub fn logout(callback: Callback>) -> Result { - let url = "/auth/logout"; - let request = Request::post(url).body(yew::format::Nothing)?; - let handler = create_handler(callback, |status, data: String| { - if status.is_success() { - Ok(()) - } else { - Err(anyhow!("Could not logout: [{}]: {}", status, data)) - } - }); - FetchService::fetch_with_options(request, get_default_options(), handler) + call_server( + "/auth/logout", + yew::format::Nothing, + callback, + |status, data: String| { + if status.is_success() { + Ok(()) + } else { + Err(anyhow!("Could not logout: [{}]: {}", status, data)) + } + }, + ) } pub fn create_user( request: CreateUserRequest, callback: Callback>, ) -> Result { - let url = "/api/users/create"; - let request = Request::post(url) - .header("Content-Type", "application/json") - .body(Json(&request))?; - let handler = create_handler(callback, |status, data: String| { - if status.is_success() { - Ok(()) - } else { - Err(anyhow!("Could not create a user: [{}]: {}", status, data)) - } - }); - FetchService::fetch_with_options(request, get_default_options(), handler) + call_server( + "/api/users/create", + &request, + callback, + |status, data: String| { + if status.is_success() { + Ok(()) + } else { + Err(anyhow!("Could not create a user: [{}]: {}", status, data)) + } + }, + ) } }