1#[cfg(test)]
2mod tests;
3
4pub mod problem;
5pub use problem::problem;
6
7use crate::header::Header;
8use crate::request::Request;
9use crate::response::{Response, StatusCodeReasonPhrase, STATUS_CODE_REASON_PHRASE};
10
11pub trait IntoResponse {
19 fn into_response(self) -> Response;
20}
21
22impl IntoResponse for Response {
23 fn into_response(self) -> Response {
24 self
25 }
26}
27
28impl<T: IntoResponse, E: IntoResponse> IntoResponse for Result<T, E> {
31 fn into_response(self) -> Response {
32 match self {
33 Ok(value) => value.into_response(),
34 Err(error) => error.into_response(),
35 }
36 }
37}
38
39impl IntoResponse for String {
41 fn into_response(self) -> Response {
42 Response::text(STATUS_CODE_REASON_PHRASE.n200_ok, &self)
43 }
44}
45
46impl IntoResponse for &'static str {
48 fn into_response(self) -> Response {
49 Response::text(STATUS_CODE_REASON_PHRASE.n200_ok, self)
50 }
51}
52
53impl<T: IntoResponse> IntoResponse for (&'static StatusCodeReasonPhrase, T) {
56 fn into_response(self) -> Response {
57 let (status, inner) = self;
58 let mut response = inner.into_response();
59 response.status_code = *status.status_code;
60 response.reason_phrase = status.reason_phrase.to_string();
61 response
62 }
63}
64
65#[derive(Debug, PartialEq, Eq)]
86pub enum AppError {
87 BadRequest(String),
89 Unauthorized,
91 Forbidden,
93 NotFound(String),
95 Conflict(String),
97 UnprocessableEntity(String),
99 TooManyRequests,
101 PayloadTooLarge(String),
103 Internal(String),
105}
106
107impl IntoResponse for AppError {
108 fn into_response(self) -> Response {
109 let (status, body_str) = match &self {
110 AppError::BadRequest(msg) => (STATUS_CODE_REASON_PHRASE.n400_bad_request, msg.as_str()),
111 AppError::Unauthorized => (STATUS_CODE_REASON_PHRASE.n401_unauthorized, "Unauthorized"),
112 AppError::Forbidden => (STATUS_CODE_REASON_PHRASE.n403_forbidden, "Forbidden"),
113 AppError::NotFound(msg) => (STATUS_CODE_REASON_PHRASE.n404_not_found, msg.as_str()),
114 AppError::Conflict(msg) => (STATUS_CODE_REASON_PHRASE.n409_conflict, msg.as_str()),
115 AppError::UnprocessableEntity(msg) => (STATUS_CODE_REASON_PHRASE.n422_unprocessable_entity, msg.as_str()),
116 AppError::TooManyRequests => (STATUS_CODE_REASON_PHRASE.n429_too_many_requests, "Too Many Requests"),
117 AppError::PayloadTooLarge(msg) => (STATUS_CODE_REASON_PHRASE.n413_payload_too_large, msg.as_str()),
118 AppError::Internal(msg) => (STATUS_CODE_REASON_PHRASE.n500_internal_server_error, msg.as_str()),
119 };
120
121 let detail = match &self {
124 AppError::Unauthorized | AppError::Forbidden | AppError::TooManyRequests => "",
125 _ => body_str,
126 };
127 let dummy = Request {
128 method: "GET".to_string(),
129 request_uri: "/".to_string(),
130 http_version: "HTTP/1.1".to_string(),
131 headers: vec![],
132 body: Default::default(),
133 };
134 problem::with_headers(status, detail, body_str, Some(Header::get_header_list(&dummy)))
135 }
136}