Skip to content

Commit

Permalink
set_first_user: try improving error reporting
Browse files Browse the repository at this point in the history
Problem:

When there is an issue ("trying to use reserved username") it is reported as

> Anyhow(Backend call failed with status 422 and text '["There is a conflict between the entered\nusername and an existing username.\nTry another one."]')

(which is a wrapped `ServiceError::BackendError`)
even though the CLI is ready to handle a `ServiceError::WrongUser`

Solution:

let BaseHTTPClient::put return a deserialized response

but this commit still does not parse the JSON and does not convert the Err
  • Loading branch information
mvidner committed Jul 24, 2024
1 parent 521235b commit 5d0396e
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 15 deletions.
23 changes: 18 additions & 5 deletions rust/agama-lib/src/base_http_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,15 +129,27 @@ impl BaseHTTPClient {
///
/// * `path`: path relative to HTTP API like `/users/first`
/// * `object`: Object that can be serialiazed to JSON as body of request.
pub async fn put(&self, path: &str, object: &impl Serialize) -> Result<(), ServiceError> {
let response = self.put_response(path, object).await?;
pub async fn put<T>(&self, path: &str, object: &impl Serialize) -> Result<T, ServiceError>
where
T: DeserializeOwned + std::fmt::Debug,
{
let response = self.request_response(reqwest::Method::PUT, path, object).await?;
if response.status().is_success() {
Ok(())
if let Some(clen) = response.content_length() {
if clen == 0 {
println!("empty body");
}
}

let ret = response.json::<T>().await.map_err(|e| e.into());
println!("PUT returns: {:#?}", ret);
ret
} else {
Err(self.build_backend_error(response).await)
}
}

/// FIXME redoc
/// post object to given path and returns server response. Reports error only if failed to send
/// request, but if server returns e.g. 500, it will be in Ok result.
///
Expand All @@ -147,13 +159,14 @@ impl BaseHTTPClient {
///
/// * `path`: path relative to HTTP API like `/questions`
/// * `object`: Object that can be serialiazed to JSON as body of request.
pub async fn put_response(
pub async fn request_response(
&self,
method: reqwest::Method,
path: &str,
object: &impl Serialize,
) -> Result<Response, ServiceError> {
self.client
.put(self.url(path))
.request(method, self.url(path))
.json(object)
.send()
.await
Expand Down
13 changes: 10 additions & 3 deletions rust/agama-lib/src/users/http_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,16 @@ impl UsersHttpClient {
&self,
first_user: &FirstUser,
) -> Result<(bool, Vec<String>), ServiceError> {
self.client.put("/users/first", first_user).await?;
// TODO: make BaseHTTPClient.put(_response) return the issues
Ok((true, vec!()))
let result: Result<Vec<String>, ServiceError> = self.client.put("/users/first", first_user).await;
if let Err(ServiceError::BackendError(422, ref issues_s)) = result {
// way to go:
// deserialize json from string
// and use (void) put
println!("ISSUUUS {}", issues_s);
}

let issues = result?;
Ok((issues.is_empty(), issues))
}

async fn root_config(&self) -> Result<RootConfig, ServiceError> {
Expand Down
16 changes: 9 additions & 7 deletions rust/agama-server/src/users/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,15 +175,17 @@ async fn set_first_user(
// issues: for example, trying to use a system user id; empty password
// success: simply !issues.is_empty()
let (_success, issues) = state.users.set_first_user(&config).await?;
if issues.is_empty() {
Ok((StatusCode::NO_CONTENT, ().into_response()))
let status = if issues.is_empty() {
StatusCode::OK
}
else {
Ok((
StatusCode::UNPROCESSABLE_ENTITY,
Json(issues).into_response(),
))
}
StatusCode::UNPROCESSABLE_ENTITY
};

Ok((
status,
Json(issues).into_response(),
))
}

#[utoipa::path(get, path = "/users/first", responses(
Expand Down

0 comments on commit 5d0396e

Please sign in to comment.