app: refactor API methods with empty responses

This commit is contained in:
Valentin Tolmer 2021-08-27 00:12:46 +02:00 committed by nitnelave
parent f860b8fe43
commit a1f40a32a5
2 changed files with 76 additions and 77 deletions

View File

@ -57,18 +57,18 @@ impl From<yew::format::Nothing> for RequestBody<yew::format::Nothing> {
} }
} }
fn call_server<Req, CallbackResult, Resp, F, RB>( fn call_server<Req, CallbackResult, F, RB>(
url: &str, url: &str,
request: RB, request: RB,
callback: Callback<Result<CallbackResult>>, callback: Callback<Result<CallbackResult>>,
handler: F, error_message: &'static str,
parse_response: F,
) -> Result<FetchTask> ) -> Result<FetchTask>
where where
F: Fn(http::StatusCode, Resp) -> Result<CallbackResult> + 'static, F: Fn(String) -> Result<CallbackResult> + 'static,
CallbackResult: 'static, CallbackResult: 'static,
RB: Into<RequestBody<Req>>, RB: Into<RequestBody<Req>>,
Req: Into<yew::format::Text>, Req: Into<yew::format::Text>,
Result<Resp>: From<Result<String>> + 'static,
{ {
let request = { let request = {
// If the request type is empty (if the size is 0), it's a get. // If the request type is empty (if the size is 0), it's a get.
@ -80,7 +80,13 @@ where
} }
.header("Content-Type", "application/json") .header("Content-Type", "application/json")
.body(request.into().0)?; .body(request.into().0)?;
let handler = create_handler(callback, handler); let handler = create_handler(callback, move |status: http::StatusCode, data: String| {
if status.is_success() {
parse_response(data)
} else {
Err(anyhow!("{}[{}]: {}", error_message, status, data))
}
});
FetchService::fetch_with_options(request, get_default_options(), handler) FetchService::fetch_with_options(request, get_default_options(), handler)
} }
@ -94,18 +100,28 @@ where
CallbackResult: serde::de::DeserializeOwned + 'static, CallbackResult: serde::de::DeserializeOwned + 'static,
RB: Into<RequestBody<Req>>, RB: Into<RequestBody<Req>>,
Req: Into<yew::format::Text>, Req: Into<yew::format::Text>,
{
call_server(url, request, callback, error_message, |data: String| {
serde_json::from_str(&data).context("Could not parse response")
})
}
fn call_server_empty_response_with_error_message<RB, Req>(
url: &str,
request: RB,
callback: Callback<Result<()>>,
error_message: &'static str,
) -> Result<FetchTask>
where
RB: Into<RequestBody<Req>>,
Req: Into<yew::format::Text>,
{ {
call_server( call_server(
url, url,
request, request,
callback, callback,
move |status: http::StatusCode, data: String| { error_message,
if status.is_success() { |_data: String| Ok(()),
serde_json::from_str(&data).context("Could not parse response")
} else {
Err(anyhow!("{}[{}]: {}", error_message, status, data))
}
},
) )
} }
@ -118,22 +134,31 @@ impl HostService {
where where
QueryType: GraphQLQuery + 'static, QueryType: GraphQLQuery + 'static,
{ {
let unwrap_graphql_response = |graphql_client::Response { data, errors }| {
data.ok_or_else(|| {
anyhow!(
"Errors: [{}]",
errors
.unwrap_or_default()
.iter()
.map(ToString::to_string)
.collect::<Vec<_>>()
.join(", ")
)
})
};
let parse_graphql_response = move |data: String| {
serde_json::from_str(&data)
.context("Could not parse response")
.and_then(unwrap_graphql_response)
};
let request_body = QueryType::build_query(variables); let request_body = QueryType::build_query(variables);
call_server( call_server(
"/api/graphql", "/api/graphql",
&request_body, &request_body,
callback, callback,
move |status: http::StatusCode, data: String| { error_message,
if status.is_success() { parse_graphql_response,
serde_json::from_str(&data)
.context("Could not parse response")
.and_then(|graphql_client::Response { data, errors }| {
data.ok_or_else(|| anyhow!("Errors: {:?}", errors.unwrap_or(vec![])))
})
} else {
Err(anyhow!("{}[{}]: {}", error_message, status, data))
}
},
) )
} }
@ -162,31 +187,24 @@ impl HostService {
request: login::ClientLoginFinishRequest, request: login::ClientLoginFinishRequest,
callback: Callback<Result<(String, bool)>>, callback: Callback<Result<(String, bool)>>,
) -> Result<FetchTask> { ) -> Result<FetchTask> {
let set_cookies = |jwt_claims: JWTClaims| {
let is_admin = jwt_claims.groups.contains("lldap_admin");
set_cookie("user_id", &jwt_claims.user, &jwt_claims.exp)
.map(|_| set_cookie("is_admin", &is_admin.to_string(), &jwt_claims.exp))
.map(|_| (jwt_claims.user.clone(), is_admin))
.context("Error clearing cookie")
};
let parse_token = move |data: String| {
get_claims_from_jwt(&data)
.context("Could not parse response")
.and_then(set_cookies)
};
call_server( call_server(
"/auth/opaque/login/finish", "/auth/opaque/login/finish",
&request, &request,
callback, callback,
|status, data: String| { "Could not finish authentication",
if status.is_success() { parse_token,
get_claims_from_jwt(&data)
.context("Could not parse response")
.and_then(|jwt_claims| {
let is_admin = jwt_claims.groups.contains("lldap_admin");
set_cookie("user_id", &jwt_claims.user, &jwt_claims.exp)
.map(|_| {
set_cookie("is_admin", &is_admin.to_string(), &jwt_claims.exp)
})
.map(|_| (jwt_claims.user.clone(), is_admin))
.context("Error clearing cookie")
})
} else {
Err(anyhow!(
"Could not finish authentication: [{}]: {}",
status,
data
))
}
},
) )
} }
@ -206,32 +224,20 @@ impl HostService {
request: registration::ClientRegistrationFinishRequest, request: registration::ClientRegistrationFinishRequest,
callback: Callback<Result<()>>, callback: Callback<Result<()>>,
) -> Result<FetchTask> { ) -> Result<FetchTask> {
call_server( call_server_empty_response_with_error_message(
"/auth/opaque/registration/finish", "/auth/opaque/registration/finish",
&request, &request,
callback, callback,
|status, data: String| { "Could not finish registration",
if status.is_success() {
Ok(())
} else {
Err(anyhow!("Could finish registration: [{}]: {}", status, data))
}
},
) )
} }
pub fn logout(callback: Callback<Result<()>>) -> Result<FetchTask> { pub fn logout(callback: Callback<Result<()>>) -> Result<FetchTask> {
call_server( call_server_empty_response_with_error_message(
"/auth/logout", "/auth/logout",
yew::format::Nothing, yew::format::Nothing,
callback, callback,
|status, data: String| { "Could not logout",
if status.is_success() {
Ok(())
} else {
Err(anyhow!("Could not logout: [{}]: {}", status, data))
}
},
) )
} }
@ -239,17 +245,11 @@ impl HostService {
request: CreateUserRequest, request: CreateUserRequest,
callback: Callback<Result<()>>, callback: Callback<Result<()>>,
) -> Result<FetchTask> { ) -> Result<FetchTask> {
call_server( call_server_empty_response_with_error_message(
"/api/users/create", "/api/users/create",
&request, &request,
callback, callback,
|status, data: String| { "Could not create a user",
if status.is_success() {
Ok(())
} else {
Err(anyhow!("Could not create a user: [{}]: {}", status, data))
}
},
) )
} }
} }

View File

@ -24,17 +24,16 @@ pub enum Msg {
impl UserTable { impl UserTable {
fn get_users(&mut self, req: Option<RequestFilter>) { fn get_users(&mut self, req: Option<RequestFilter>) {
match HostService::graphql_query::<ListUsersQuery>( self._task = HostService::graphql_query::<ListUsersQuery>(
list_users_query::Variables { filters: req }, list_users_query::Variables { filters: req },
self.link.callback(Msg::ListUsersResponse), self.link.callback(Msg::ListUsersResponse),
"", "Error trying to fetch users",
) { )
Ok(task) => self._task = Some(task), .map_err(|e| {
Err(e) => { ConsoleService::log(&e.to_string());
self._task = None; e
ConsoleService::log(format!("Error trying to fetch users: {}", e).as_str()) })
} .ok();
};
} }
} }