Skip to content

Commit

Permalink
add error details to other errors
Browse files Browse the repository at this point in the history
  • Loading branch information
kentSarmiento committed Dec 26, 2023
1 parent 865c2ff commit 6eae0a9
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 80 deletions.
61 changes: 41 additions & 20 deletions link-for-later/src/controller/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use serde_json::json;

use crate::types::AppError;

#[allow(clippy::cognitive_complexity)]
impl IntoResponse for AppError {
fn into_response(self) -> Response {
let (status, error_message) = match self {
Expand All @@ -18,16 +19,30 @@ impl IntoResponse for AppError {
tracing::debug!("Database error: {}", e.to_string());
(StatusCode::INTERNAL_SERVER_ERROR, self.to_string())
}
Self::LinkNotFound => (StatusCode::NOT_FOUND, self.to_string()),
Self::UserAlreadyExists
| Self::UserNotFound
| Self::InvalidEmail
| Self::InvalidUrl => (StatusCode::BAD_REQUEST, self.to_string()),
Self::IncorrectPassword => (StatusCode::UNAUTHORIZED, self.to_string()),
Self::LinkNotFound(ref e) => {
tracing::debug!("Link not found: {}", e.to_string());
(StatusCode::NOT_FOUND, self.to_string())
}
Self::UserAlreadyExists(ref e) => {
tracing::debug!("User already exists: {}", e.to_string());
(StatusCode::BAD_REQUEST, self.to_string())
}
Self::UserNotFound(ref e) => {
tracing::debug!("User not found: {}", e.to_string());
(StatusCode::BAD_REQUEST, self.to_string())
}
Self::IncorrectPassword(ref e) => {
tracing::debug!("Incorrect password: {}", e.to_string());
(StatusCode::UNAUTHORIZED, self.to_string())
}
Self::AuthorizationError(ref e) => {
tracing::debug!("Authorization error: {}", e.to_string());
(StatusCode::UNAUTHORIZED, self.to_string())
}
Self::ValidationError(ref e) => {
tracing::debug!("Payload validation error: {}", e.to_string());
(StatusCode::BAD_REQUEST, self.to_string())
}

#[cfg(test)]
Self::TestError => (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()),
Expand All @@ -49,46 +64,52 @@ mod tests {
#[test]
fn test_error_response() {
assert_eq!(
AppError::ServerError("server error occurred".into())
AppError::ServerError("a server operation failed".into())
.into_response()
.status(),
StatusCode::INTERNAL_SERVER_ERROR
);
assert_eq!(
AppError::DatabaseError("database error occurred".into())
AppError::DatabaseError("a database operation failed".into())
.into_response()
.status(),
StatusCode::INTERNAL_SERVER_ERROR
);
assert_eq!(
AppError::LinkNotFound.into_response().status(),
AppError::LinkNotFound("link".into())
.into_response()
.status(),
StatusCode::NOT_FOUND
);
assert_eq!(
AppError::UserAlreadyExists.into_response().status(),
StatusCode::BAD_REQUEST
);
assert_eq!(
AppError::UserNotFound.into_response().status(),
AppError::UserAlreadyExists("user".into())
.into_response()
.status(),
StatusCode::BAD_REQUEST
);
assert_eq!(
AppError::InvalidEmail.into_response().status(),
AppError::UserNotFound("user".into())
.into_response()
.status(),
StatusCode::BAD_REQUEST
);
assert_eq!(
AppError::InvalidUrl.into_response().status(),
StatusCode::BAD_REQUEST
AppError::IncorrectPassword("user".into())
.into_response()
.status(),
StatusCode::UNAUTHORIZED
);
assert_eq!(
AppError::IncorrectPassword.into_response().status(),
AppError::AuthorizationError("an authorization error occurred".into())
.into_response()
.status(),
StatusCode::UNAUTHORIZED
);
assert_eq!(
AppError::AuthorizationError("authorization error occurred".into())
AppError::ValidationError("a validation error occurred".into())
.into_response()
.status(),
StatusCode::UNAUTHORIZED
StatusCode::BAD_REQUEST
);
}
}
10 changes: 4 additions & 6 deletions link-for-later/src/controller/links.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@ async fn post(
match payload.validate() {
Ok(()) => {}
Err(e) => {
tracing::error!("Error: {}", e);
return AppError::InvalidUrl.into_response();
return AppError::ValidationError(format!("post_link() {e:?}")).into_response();
}
}

Expand Down Expand Up @@ -105,8 +104,7 @@ async fn put(
match payload.validate() {
Ok(()) => {}
Err(e) => {
tracing::error!("Error: {}", e);
return AppError::InvalidUrl.into_response();
return AppError::ValidationError(format!("put_link() {e:?}")).into_response();
}
}

Expand Down Expand Up @@ -301,7 +299,7 @@ mod tests {

let body = body.collect().await.unwrap().to_bytes();
let body = std::str::from_utf8(&body).unwrap();
assert_eq!(body, json!({"error": "invalid url"}).to_string());
assert_eq!(body, json!({"error": "invalid request"}).to_string());
}

#[traced_test]
Expand Down Expand Up @@ -458,7 +456,7 @@ mod tests {

let body = body.collect().await.unwrap().to_bytes();
let body = std::str::from_utf8(&body).unwrap();
assert_eq!(body, json!({"error": "invalid url"}).to_string());
assert_eq!(body, json!({"error": "invalid request"}).to_string());
}

#[traced_test]
Expand Down
10 changes: 4 additions & 6 deletions link-for-later/src/controller/users.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ async fn register(
match payload.validate() {
Ok(()) => {}
Err(e) => {
tracing::error!("Error: {}", e);
return AppError::InvalidEmail.into_response();
return AppError::ValidationError(format!("register() {e:?}")).into_response();
}
}

Expand All @@ -58,8 +57,7 @@ async fn login(
match payload.validate() {
Ok(()) => {}
Err(e) => {
tracing::error!("Error: {}", e);
return AppError::InvalidEmail.into_response();
return AppError::ValidationError(format!("login() {e:?}")).into_response();
}
}

Expand Down Expand Up @@ -141,7 +139,7 @@ mod tests {

let body = body.collect().await.unwrap().to_bytes();
let body = std::str::from_utf8(&body).unwrap();
assert_eq!(body, json!({"error": "invalid email"}).to_string());
assert_eq!(body, json!({"error": "invalid request"}).to_string());
}

#[traced_test]
Expand Down Expand Up @@ -209,7 +207,7 @@ mod tests {

let body = body.collect().await.unwrap().to_bytes();
let body = std::str::from_utf8(&body).unwrap();
assert_eq!(body, json!({"error": "invalid email"}).to_string());
assert_eq!(body, json!({"error": "invalid request"}).to_string());
}

#[traced_test]
Expand Down
6 changes: 3 additions & 3 deletions link-for-later/src/repository/inmemory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ impl LinksRepository for LinksRepositoryProvider {
.iter()
.find(|link| link.id() == query.id() && link.owner() == query.owner())
.cloned()
.ok_or(AppError::LinkNotFound)
.ok_or_else(|| AppError::LinkNotFound(query.id().to_owned()))
}

async fn create(&self, item: &LinkItem) -> Result<LinkItem> {
Expand All @@ -66,7 +66,7 @@ impl LinksRepository for LinksRepositoryProvider {
.iter()
.find(|link| link.id() == id && link.owner() == item.owner())
.cloned()
.ok_or(AppError::LinkNotFound)?;
.ok_or_else(|| AppError::LinkNotFound(id.to_owned()))?;
self.delete(item).await?;
INMEMORY_LINKS_DATA.lock().unwrap().push(item.clone());
Ok(item.clone())
Expand All @@ -92,7 +92,7 @@ impl UsersRepository for UsersRepositoryProvider {
.iter()
.find(|user| user.email() == query.email())
.cloned()
.ok_or(AppError::UserNotFound)
.ok_or_else(|| AppError::UserNotFound(query.email().to_owned()))
}

async fn create(&self, info: &UserInfo) -> Result<UserInfo> {
Expand Down
4 changes: 2 additions & 2 deletions link-for-later/src/repository/mongodb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ impl LinksRepository for LinksRepositoryProvider {
.find_one(db_query, None)
.await
.map_err(|e| AppError::DatabaseError(format!("find_one() {e:?}")))?;
item.ok_or(AppError::LinkNotFound)
item.ok_or_else(|| AppError::LinkNotFound(query.id().to_owned()))
}

async fn create(&self, item: &LinkItem) -> Result<LinkItem> {
Expand Down Expand Up @@ -123,7 +123,7 @@ impl UsersRepository for UsersRepositoryProvider {
.find_one(db_query, None)
.await
.map_err(|e| AppError::DatabaseError(format!("find_one() {e:?}")))?;
item.ok_or(AppError::UserNotFound)
item.ok_or_else(|| AppError::UserNotFound(query.email().to_owned()))
}

async fn create(&self, info: &UserInfo) -> Result<UserInfo> {
Expand Down
12 changes: 6 additions & 6 deletions link-for-later/src/service/links.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,14 +193,14 @@ mod tests {
.expect_get()
.withf(move |query| query == &repo_query)
.times(1)
.returning(|_| Err(AppError::LinkNotFound));
.returning(|_| Err(AppError::LinkNotFound("1".into())));

let links_service = ServiceProvider {};
let response = links_service
.get(Box::new(Arc::new(mock_links_repo)), &request_query)
.await;

assert_eq!(response, Err(AppError::LinkNotFound));
assert_eq!(response, Err(AppError::LinkNotFound("1".into())));
}

#[tokio::test]
Expand Down Expand Up @@ -307,7 +307,7 @@ mod tests {
.expect_get()
.withf(move |query| query == &repo_query)
.times(1)
.returning(|_| Err(AppError::LinkNotFound));
.returning(|_| Err(AppError::LinkNotFound("1".into())));
mock_links_repo
.expect_update()
//.withf(move |item| item == &item_to_update)
Expand All @@ -318,7 +318,7 @@ mod tests {
.update(Box::new(Arc::new(mock_links_repo)), "1", &request_item)
.await;

assert_eq!(response, Err(AppError::LinkNotFound));
assert_eq!(response, Err(AppError::LinkNotFound("1".into())));
}

#[tokio::test]
Expand Down Expand Up @@ -409,7 +409,7 @@ mod tests {
.expect_get()
.withf(move |query| query == &repo_query)
.times(1)
.returning(|_| Err(AppError::LinkNotFound));
.returning(|_| Err(AppError::LinkNotFound("1".into())));
mock_links_repo
.expect_delete()
//.withf(move |item| item == &item_to_delete)
Expand All @@ -420,7 +420,7 @@ mod tests {
.delete(Box::new(Arc::new(mock_links_repo)), &request_item)
.await;

assert_eq!(response, Err(AppError::LinkNotFound));
assert_eq!(response, Err(AppError::LinkNotFound("1".into())));
}

#[tokio::test]
Expand Down
28 changes: 18 additions & 10 deletions link-for-later/src/service/users.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ impl UsersService for ServiceProvider {
) -> Result<UserInfo> {
let user_query = UserQueryBuilder::new(user_info.email()).build();
let user_info = match users_repo.get(&user_query).await {
Ok(_) => return Err(AppError::UserAlreadyExists),
Err(AppError::UserNotFound) => user_info.clone(),
Ok(_) => return Err(AppError::UserAlreadyExists(user_info.email().to_owned())),
Err(AppError::UserNotFound(_)) => user_info.clone(),
Err(e) => return Err(e),
};

Expand All @@ -52,8 +52,7 @@ impl UsersService for ServiceProvider {
let retrieved_user_info = users_repo.get(&user_query).await?;

if retrieved_user_info.password() != user_info.password() {
tracing::info!("invalid password for user {}", &user_info.email());
return Err(AppError::IncorrectPassword);
return Err(AppError::IncorrectPassword(user_info.email().to_owned()));
}

let timestamp = |timestamp: DateTime<Utc>| -> Result<usize> {
Expand Down Expand Up @@ -106,7 +105,7 @@ mod tests {
.expect_get()
.withf(move |query| query == &repo_query)
.times(1)
.returning(|_| Err(AppError::UserNotFound));
.returning(|_| Err(AppError::UserNotFound("[email protected]".into())));
mock_users_repo
.expect_create()
//.withf(move |user| user == &user_to_register)
Expand Down Expand Up @@ -142,7 +141,10 @@ mod tests {
.register(Box::new(Arc::new(mock_users_repo)), &request_item)
.await;

assert_eq!(response, Err(AppError::UserAlreadyExists));
assert_eq!(
response,
Err(AppError::UserAlreadyExists("[email protected]".into()))
);
}

#[tokio::test]
Expand Down Expand Up @@ -178,7 +180,7 @@ mod tests {
.expect_get()
.withf(move |query| query == &repo_query)
.times(1)
.returning(|_| Err(AppError::UserNotFound));
.returning(|_| Err(AppError::UserNotFound("[email protected]".into())));
mock_users_repo
.expect_create()
//.withf(move |user| user == &user_to_register)
Expand Down Expand Up @@ -226,14 +228,17 @@ mod tests {
.expect_get()
.withf(move |query| query == &repo_query)
.times(1)
.returning(move |_| Err(AppError::UserNotFound));
.returning(move |_| Err(AppError::UserNotFound("[email protected]".into())));

let users_service = ServiceProvider {};
let response = users_service
.login(Box::new(Arc::new(mock_users_repo)), &request_item)
.await;

assert_eq!(response, Err(AppError::UserNotFound));
assert_eq!(
response,
Err(AppError::UserNotFound("[email protected]".into()))
);
}

#[tokio::test]
Expand All @@ -255,6 +260,9 @@ mod tests {
.login(Box::new(Arc::new(mock_users_repo)), &request_item)
.await;

assert_eq!(response, Err(AppError::IncorrectPassword));
assert_eq!(
response,
Err(AppError::IncorrectPassword("[email protected]".into()))
);
}
}
Loading

0 comments on commit 6eae0a9

Please sign in to comment.