1#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
2#[error("{message}")]
3pub struct Error {
5 status: Option<u16>,
6 message: String,
7 expose_message: bool,
8}
9
10pub(crate) const HTTP_BAD_REQUEST: u16 = 400;
11pub(crate) const HTTP_UNAUTHORIZED: u16 = 401;
12pub(crate) const HTTP_FORBIDDEN: u16 = 403;
13pub(crate) const HTTP_NOT_FOUND: u16 = 404;
14pub(crate) const HTTP_CONFLICT: u16 = 409;
15pub(crate) const HTTP_PRECONDITION_FAILED: u16 = 412;
16pub(crate) const HTTP_INTERNAL_SERVER_ERROR: u16 = 500;
17pub(crate) const HTTP_NOT_IMPLEMENTED: u16 = 501;
18pub(crate) const HTTP_UNAVAILABLE: u16 = 503;
19pub(crate) const INTERNAL_ERROR_MESSAGE: &str = "internal error";
20
21pub type Result<T> = std::result::Result<T, Error>;
23
24impl Error {
25 pub fn new(message: impl Into<String>) -> Self {
27 Self {
28 status: None,
29 message: message.into(),
30 expose_message: true,
31 }
32 }
33
34 pub fn with_status(status: u16, message: impl Into<String>) -> Self {
36 Self {
37 status: Some(status),
38 message: message.into(),
39 expose_message: true,
40 }
41 }
42
43 pub fn bad_request(message: impl Into<String>) -> Self {
45 Self::with_status(HTTP_BAD_REQUEST, message)
46 }
47
48 pub fn internal(message: impl Into<String>) -> Self {
50 Self::with_status(HTTP_INTERNAL_SERVER_ERROR, message)
51 }
52
53 pub fn not_found(message: impl Into<String>) -> Self {
55 Self::with_status(HTTP_NOT_FOUND, message)
56 }
57
58 pub fn already_exists(message: impl Into<String>) -> Self {
60 Self::with_status(HTTP_CONFLICT, message)
61 }
62
63 pub fn failed_precondition(message: impl Into<String>) -> Self {
65 Self::with_status(HTTP_PRECONDITION_FAILED, message)
66 }
67
68 pub fn unavailable(message: impl Into<String>) -> Self {
70 Self::with_status(HTTP_UNAVAILABLE, message)
71 }
72
73 pub fn unauthenticated(message: impl Into<String>) -> Self {
75 Self::with_status(HTTP_UNAUTHORIZED, message)
76 }
77
78 pub fn permission_denied(message: impl Into<String>) -> Self {
80 Self::with_status(HTTP_FORBIDDEN, message)
81 }
82
83 pub fn unimplemented(message: impl Into<String>) -> Self {
85 Self::with_status(HTTP_NOT_IMPLEMENTED, message)
86 }
87
88 pub fn status(&self) -> Option<u16> {
91 self.status
92 }
93
94 pub fn message(&self) -> &str {
96 &self.message
97 }
98
99 pub(crate) fn expose_message(&self) -> bool {
100 self.expose_message
101 }
102
103 pub(crate) fn hidden_internal(message: impl Into<String>) -> Self {
104 Self {
105 status: Some(HTTP_INTERNAL_SERVER_ERROR),
106 message: message.into(),
107 expose_message: false,
108 }
109 }
110}
111
112impl From<serde_json::Error> for Error {
113 fn from(value: serde_json::Error) -> Self {
114 Self::hidden_internal(value.to_string())
115 }
116}
117
118impl From<std::io::Error> for Error {
119 fn from(value: std::io::Error) -> Self {
120 Self::hidden_internal(value.to_string())
121 }
122}
123
124impl From<tonic::transport::Error> for Error {
125 fn from(value: tonic::transport::Error) -> Self {
126 Self::hidden_internal(value.to_string())
127 }
128}