feat(DRW-001) initial commit!
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
use axum::http::StatusCode;
|
||||
use axum::response::{IntoResponse, Response};
|
||||
use axum::Json;
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct ErrorBody {
|
||||
error: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AppError {
|
||||
Internal,
|
||||
NotFound,
|
||||
BadRequest(String),
|
||||
}
|
||||
|
||||
impl IntoResponse for AppError {
|
||||
fn into_response(self) -> Response {
|
||||
let (status, message) = match self {
|
||||
AppError::Internal => (StatusCode::INTERNAL_SERVER_ERROR, "internal server error".to_string()),
|
||||
AppError::NotFound => (StatusCode::NOT_FOUND, "not found".to_string()),
|
||||
AppError::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg),
|
||||
};
|
||||
(status, Json(ErrorBody { error: message })).into_response()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<sqlx::Error> for AppError {
|
||||
fn from(e: sqlx::Error) -> Self {
|
||||
tracing::error!("{e}");
|
||||
AppError::Internal
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
async fn body_json(error: AppError) -> serde_json::Value {
|
||||
let response = error.into_response();
|
||||
let bytes = axum::body::to_bytes(response.into_body(), usize::MAX).await.unwrap();
|
||||
serde_json::from_slice(&bytes).unwrap()
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn internal_maps_to_500_with_error_body() {
|
||||
let response = AppError::Internal.into_response();
|
||||
assert_eq!(response.status(), StatusCode::INTERNAL_SERVER_ERROR);
|
||||
|
||||
let body = body_json(AppError::Internal).await;
|
||||
assert_eq!(body["error"], "internal server error");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn not_found_maps_to_404_with_error_body() {
|
||||
let response = AppError::NotFound.into_response();
|
||||
assert_eq!(response.status(), StatusCode::NOT_FOUND);
|
||||
|
||||
let body = body_json(AppError::NotFound).await;
|
||||
assert_eq!(body["error"], "not found");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn bad_request_maps_to_400_and_carries_its_message() {
|
||||
let response = AppError::BadRequest("nope".to_string()).into_response();
|
||||
assert_eq!(response.status(), StatusCode::BAD_REQUEST);
|
||||
|
||||
let body = body_json(AppError::BadRequest("nope".to_string())).await;
|
||||
assert_eq!(body["error"], "nope");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn sqlx_errors_map_to_internal() {
|
||||
let sqlx_err = sqlx::Error::RowNotFound;
|
||||
let app_err: AppError = sqlx_err.into();
|
||||
assert!(matches!(app_err, AppError::Internal));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user