error.rs 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. use std::io;
  2. use actix_web::{HttpResponse, ResponseError, http::StatusCode};
  3. use serde::Serialize;
  4. use thiserror::Error;
  5. pub type AppResult<T> = Result<T, AppError>;
  6. #[derive(Debug, Error)]
  7. pub enum AppError {
  8. #[error("I/O error: {0}")]
  9. Io(#[from] io::Error),
  10. #[error("database error: {0}")]
  11. Db(#[from] rusqlite::Error),
  12. #[error("configuration parse error: {0}")]
  13. Config(toml::de::Error),
  14. #[error("validation error: {0}")]
  15. Validation(String),
  16. #[error("conflict: {0}")]
  17. Conflict(String),
  18. #[error("not found: {0}")]
  19. NotFound(String),
  20. #[error("unauthorized: {0}")]
  21. Unauthorized(String),
  22. #[error("forbidden: {0}")]
  23. Forbidden(String),
  24. #[error("git error: {0}")]
  25. Git(String),
  26. }
  27. #[derive(Serialize)]
  28. struct ErrorBody {
  29. code: &'static str,
  30. message: String,
  31. status: u16,
  32. }
  33. impl ResponseError for AppError {
  34. fn status_code(&self) -> StatusCode {
  35. match self {
  36. AppError::Validation(_) => StatusCode::BAD_REQUEST,
  37. AppError::Conflict(_) => StatusCode::CONFLICT,
  38. AppError::NotFound(_) => StatusCode::NOT_FOUND,
  39. AppError::Unauthorized(_) => StatusCode::UNAUTHORIZED,
  40. AppError::Forbidden(_) => StatusCode::FORBIDDEN,
  41. AppError::Io(_) | AppError::Db(_) | AppError::Config(_) | AppError::Git(_) => {
  42. StatusCode::INTERNAL_SERVER_ERROR
  43. }
  44. }
  45. }
  46. fn error_response(&self) -> HttpResponse {
  47. HttpResponse::build(self.status_code()).json(ErrorBody {
  48. code: self.code(),
  49. message: self.public_message(),
  50. status: self.status_code().as_u16(),
  51. })
  52. }
  53. }
  54. impl AppError {
  55. fn code(&self) -> &'static str {
  56. match self {
  57. AppError::Validation(_) => "validation_error",
  58. AppError::Conflict(_) => "conflict",
  59. AppError::NotFound(_) => "not_found",
  60. AppError::Unauthorized(_) => "unauthorized",
  61. AppError::Forbidden(_) => "forbidden",
  62. AppError::Io(_) | AppError::Db(_) | AppError::Config(_) | AppError::Git(_) => {
  63. "internal_error"
  64. }
  65. }
  66. }
  67. fn public_message(&self) -> String {
  68. match self {
  69. AppError::Validation(message)
  70. | AppError::Conflict(message)
  71. | AppError::NotFound(message)
  72. | AppError::Unauthorized(message)
  73. | AppError::Forbidden(message) => message.clone(),
  74. AppError::Io(_) | AppError::Db(_) | AppError::Config(_) | AppError::Git(_) => {
  75. "internal server error".to_string()
  76. }
  77. }
  78. }
  79. }