Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: base client error off response status code #470

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 19 additions & 12 deletions cargo-shuttle/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::fmt::Write;
use anyhow::{Context, Result};
use async_trait::async_trait;
use headers::{Authorization, HeaderMapExt};
use reqwest::{Body, Response};
use reqwest::{Body, Response, StatusCode};
use reqwest_middleware::{ClientBuilder, ClientWithMiddleware, RequestBuilder};
use reqwest_retry::policies::ExponentialBackoff;
use reqwest_retry::RetryTransientMiddleware;
Expand Down Expand Up @@ -31,23 +31,30 @@ trait ToJson {
#[async_trait]
impl ToJson for Response {
async fn to_json<T: DeserializeOwned>(self) -> Result<T> {
let status_code = self.status();
let full = self.bytes().await?;

trace!(
response = std::str::from_utf8(&full).unwrap_or_default(),
"parsing response to json"
);
// try to deserialize into calling function response model
match serde_json::from_slice(&full) {
Ok(res) => Ok(res),
Err(_) => {
trace!("parsing response to common error");
// if that doesn't work, try to deserialize into common error type
let res: error::ApiError =
serde_json::from_slice(&full).context("failed to parse response to JSON")?;

Err(res.into())
}

if matches!(
status_code,
StatusCode::OK | StatusCode::SWITCHING_PROTOCOLS
chesedo marked this conversation as resolved.
Show resolved Hide resolved
) {
serde_json::from_slice(&full).context("failed to parse a successfull response")
} else {
trace!("parsing response to common error");
let res: error::ApiError = match serde_json::from_slice(&full) {
Ok(res) => res,
_ => {
trace!("getting error from status code");
status_code.into()
}
};

Err(res.into())
}
}
}
Expand Down
38 changes: 38 additions & 0 deletions common/src/models/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use comfy_table::Color;
use crossterm::style::Stylize;
use http::StatusCode;
use serde::{Deserialize, Serialize};
use tracing::{error, log::warn};

#[derive(Serialize, Deserialize, Debug)]
pub struct ApiError {
Expand Down Expand Up @@ -90,3 +91,40 @@ impl From<ErrorKind> for ApiError {
}
}
}

impl From<StatusCode> for ApiError {
fn from(code: StatusCode) -> Self {
let message = match code {
StatusCode::OK | StatusCode::ACCEPTED | StatusCode::FOUND | StatusCode::SWITCHING_PROTOCOLS => {
unreachable!("we should not have an API error with a successfull status code")
}
StatusCode::FORBIDDEN => "this request is not allowed",
StatusCode::UNAUTHORIZED => {
"we we're able to authorize your request. Is your key still valid?"
chesedo marked this conversation as resolved.
Show resolved Hide resolved
},
StatusCode::INTERNAL_SERVER_ERROR => "our server was unable to handle your request. A ticket should be created for us to fix this.",
StatusCode::SERVICE_UNAVAILABLE => "we're experiencing a high workload right now, please try again in a little bit",
StatusCode::BAD_REQUEST => {
warn!("responding to a BAD_REQUEST request with an unhelpful message. Use ErrorKind instead");
"this request is invalid"
},
StatusCode::NOT_FOUND => {
warn!("responding to a NOT_FOUND request with an unhelpful message. Use ErrorKind instead");
"we don't serve this resource"
},
StatusCode::BAD_GATEWAY => {
warn!("got a bad response from a deployer");
"response from deployer is invalid. Please create a ticket to report this"
},
_ => {
error!(%code, "got an unexpected status code");
"an unexpected error occured. Please create a ticket to report this"
},
};

Self {
message: message.to_string(),
status_code: code.as_u16(),
}
}
}