forked from projectmoon/tenebrous-dicebot
Add proper error handling to web UI. Organize API client in web UI.
This commit is contained in:
parent
57ab6a51da
commit
60cf7d406a
|
@ -3481,6 +3481,7 @@ dependencies = [
|
|||
"js-sys",
|
||||
"serde",
|
||||
"tenebrous-api",
|
||||
"thiserror",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
|
|
|
@ -25,6 +25,7 @@ web-sys = "0.3"
|
|||
graphql_client = { git = "https://github.com/graphql-rust/graphql-client", branch = "master" }
|
||||
graphql_client_web = { git = "https://github.com/graphql-rust/graphql-client", branch = "master" }
|
||||
serde = { version = "1.0.67", features = ["derive"] }
|
||||
thiserror = "1.0"
|
||||
|
||||
# hopefully we can add grpc-web later instead of graphql.
|
||||
# prost = { version = "0.7.0", default-features = false }
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use graphql_client::web::Client;
|
||||
use graphql_client::web::ClientError;
|
||||
use graphql_client::GraphQLQuery;
|
||||
use graphql_client_web::Response;
|
||||
|
||||
use super::ResponseExt;
|
||||
use crate::error::UiError;
|
||||
|
||||
#[derive(GraphQLQuery)]
|
||||
#[graphql(
|
||||
|
@ -22,7 +25,7 @@ pub async fn get_user_variable(
|
|||
room_id: &str,
|
||||
user_id: &str,
|
||||
variable_name: &str,
|
||||
) -> Result<i64, ClientError> {
|
||||
) -> Result<i64, UiError> {
|
||||
let client = Client::new("http://localhost:10000/graphql");
|
||||
let variables = get_user_variable::Variables {
|
||||
room_id: room_id.to_owned(),
|
||||
|
@ -30,27 +33,20 @@ pub async fn get_user_variable(
|
|||
variable: variable_name.to_owned(),
|
||||
};
|
||||
|
||||
//TODO don't unwrap() option. map to err instead.
|
||||
let response = client.call(GetUserVariable, variables).await?;
|
||||
let response: graphql_client_web::Response<get_user_variable::ResponseData> = response;
|
||||
let value = response.data.map(|d| d.variable.value).unwrap();
|
||||
Ok(value)
|
||||
Ok(response.data()?.variable.value)
|
||||
}
|
||||
|
||||
pub async fn rooms_for_user(
|
||||
user_id: &str,
|
||||
) -> Result<Vec<rooms_for_user::RoomsForUserUserRoomsRooms>, ClientError> {
|
||||
) -> Result<Vec<rooms_for_user::RoomsForUserUserRoomsRooms>, UiError> {
|
||||
let client = Client::new("http://localhost:10000/graphql");
|
||||
let variables = rooms_for_user::Variables {
|
||||
user_id: user_id.to_owned(),
|
||||
};
|
||||
|
||||
//TODO don't unwrap() option. map to err instead.
|
||||
let response = client.call(RoomsForUser, variables).await?;
|
||||
let response: graphql_client_web::Response<rooms_for_user::ResponseData> = response;
|
||||
let rooms = response
|
||||
.data
|
||||
.map(|d| d.user_rooms.rooms)
|
||||
.unwrap_or_default();
|
||||
Ok(rooms)
|
||||
let response: Response<rooms_for_user::ResponseData> = response;
|
||||
Ok(response.data()?.user_rooms.rooms)
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
use graphql_client_web::Response;
|
||||
|
||||
use crate::error::UiError;
|
||||
|
||||
/// Extensions to the GraphQL web response type to add convenience,
|
||||
/// particularly when working with errors.
|
||||
trait ResponseExt<T> {
|
||||
/// Get the data from the response, or gather all server-side
|
||||
/// errors into a UiError variant.
|
||||
fn data(self) -> Result<T, UiError>;
|
||||
}
|
||||
|
||||
impl<T> ResponseExt<T> for Response<T> {
|
||||
fn data(self) -> Result<T, UiError> {
|
||||
let data = self.data;
|
||||
let errors = self.errors;
|
||||
|
||||
let data = data.ok_or_else(|| {
|
||||
UiError::ApiError(
|
||||
errors
|
||||
.map(|errors| {
|
||||
errors
|
||||
.into_iter()
|
||||
.map(|e| e.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(",")
|
||||
})
|
||||
.unwrap_or("unknown error".into()),
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
}
|
||||
|
||||
pub mod dicebot;
|
|
@ -0,0 +1,12 @@
|
|||
use graphql_client_web::ClientError;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum UiError {
|
||||
#[error("api client error: {0}")]
|
||||
ApiClientError(#[from] ClientError),
|
||||
|
||||
/// General API error, collecting errors from graphql server.
|
||||
#[error("error: {0}")]
|
||||
ApiError(String),
|
||||
}
|
|
@ -3,7 +3,8 @@ use wasm_bindgen::prelude::*;
|
|||
use yew::prelude::*;
|
||||
use yew_router::{components::RouterAnchor, prelude::*};
|
||||
|
||||
pub mod graphql;
|
||||
pub mod api;
|
||||
pub mod error;
|
||||
pub mod grpc;
|
||||
pub mod rooms;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::api;
|
||||
use crate::error::UiError;
|
||||
use std::sync::Arc;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen::JsValue;
|
||||
use wasm_bindgen_futures::{future_to_promise, spawn_local};
|
||||
use wasm_bindgen_futures::spawn_local;
|
||||
use web_sys::console;
|
||||
use yew::prelude::*;
|
||||
use yewdux::prelude::*;
|
||||
|
@ -59,10 +59,8 @@ fn view_room(room: &Room) -> Html {
|
|||
}
|
||||
}
|
||||
|
||||
async fn do_things(dispatch: &RoomListDispatch) {
|
||||
let rooms = crate::graphql::rooms_for_user("@projectmoon:agnos.is")
|
||||
.await
|
||||
.unwrap();
|
||||
async fn load_rooms(dispatch: &RoomListDispatch) -> Result<(), UiError> {
|
||||
let rooms = api::dicebot::rooms_for_user("@projectmoon:agnos.is").await?;
|
||||
|
||||
for room in rooms {
|
||||
dispatch.send(Action::AddRoom(Room {
|
||||
|
@ -70,6 +68,8 @@ async fn do_things(dispatch: &RoomListDispatch) {
|
|||
display_name: room.display_name,
|
||||
}));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl Component for YewduxRoomList {
|
||||
|
@ -95,7 +95,12 @@ impl Component for YewduxRoomList {
|
|||
let dispatch = dispatch.clone();
|
||||
|
||||
spawn_local(async move {
|
||||
do_things(&*dispatch).await;
|
||||
//TODO make macro to report errors in some common way:
|
||||
//handle_errors!(do_things(&*dispatch).await)
|
||||
match load_rooms(&*dispatch).await {
|
||||
Err(e) => console::log_1(&format!("Error: {:?}", e).into()),
|
||||
_ => (),
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue