Skip to content

Commit d7283ef

Browse files
committed
web/error: remove intermediate ErrorResponse type again
Saves 11 lines of code, 7 comment lines, and the indirection via intermediate type, but adds a function (`redirect_with_policy`) instead.
1 parent 3753090 commit d7283ef

File tree

1 file changed

+70
-90
lines changed

1 file changed

+70
-90
lines changed

src/web/error.rs

Lines changed: 70 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -44,93 +44,71 @@ pub enum AxumNope {
4444
// throughout instead of having the potential for a runtime error.
4545

4646
impl AxumNope {
47-
fn into_error_response(self) -> ErrorResponse {
47+
fn into_error_info(self) -> ErrorInfo {
4848
match self {
4949
AxumNope::ResourceNotFound => {
5050
// user tried to navigate to a resource (doc page/file) that doesn't exist
51-
ErrorResponse::ErrorInfo(ErrorInfo {
51+
ErrorInfo {
5252
title: "The requested resource does not exist",
5353
message: "no such resource".into(),
5454
status: StatusCode::NOT_FOUND,
55-
})
55+
}
5656
}
57-
AxumNope::BuildNotFound => ErrorResponse::ErrorInfo(ErrorInfo {
57+
AxumNope::BuildNotFound => ErrorInfo {
5858
title: "The requested build does not exist",
5959
message: "no such build".into(),
6060
status: StatusCode::NOT_FOUND,
61-
}),
61+
},
6262
AxumNope::CrateNotFound => {
6363
// user tried to navigate to a crate that doesn't exist
6464
// TODO: Display the attempted crate and a link to a search for said crate
65-
ErrorResponse::ErrorInfo(ErrorInfo {
65+
ErrorInfo {
6666
title: "The requested crate does not exist",
6767
message: "no such crate".into(),
6868
status: StatusCode::NOT_FOUND,
69-
})
69+
}
7070
}
71-
AxumNope::OwnerNotFound => ErrorResponse::ErrorInfo(ErrorInfo {
71+
AxumNope::OwnerNotFound => ErrorInfo {
7272
title: "The requested owner does not exist",
7373
message: "no such owner".into(),
7474
status: StatusCode::NOT_FOUND,
75-
}),
75+
},
7676
AxumNope::VersionNotFound => {
7777
// user tried to navigate to a crate with a version that does not exist
7878
// TODO: Display the attempted crate and version
79-
ErrorResponse::ErrorInfo(ErrorInfo {
79+
ErrorInfo {
8080
title: "The requested version does not exist",
8181
message: "no such version for this crate".into(),
8282
status: StatusCode::NOT_FOUND,
83-
})
83+
}
8484
}
8585
AxumNope::NoResults => {
8686
// user did a search with no search terms
87-
ErrorResponse::Search(Search {
88-
title: "No results given for empty search query".to_owned(),
89-
status: StatusCode::NOT_FOUND,
90-
..Default::default()
91-
})
87+
unreachable!()
9288
}
93-
AxumNope::BadRequest(source) => ErrorResponse::ErrorInfo(ErrorInfo {
89+
AxumNope::BadRequest(source) => ErrorInfo {
9490
title: "Bad request",
9591
message: Cow::Owned(source.to_string()),
9692
status: StatusCode::BAD_REQUEST,
97-
}),
98-
AxumNope::Unauthorized(what) => ErrorResponse::ErrorInfo(ErrorInfo {
93+
},
94+
AxumNope::Unauthorized(what) => ErrorInfo {
9995
title: "Unauthorized",
10096
message: what.into(),
10197
status: StatusCode::UNAUTHORIZED,
102-
}),
98+
},
10399
AxumNope::InternalError(source) => {
104100
crate::utils::report_error(&source);
105-
ErrorResponse::ErrorInfo(ErrorInfo {
101+
ErrorInfo {
106102
title: "Internal Server Error",
107103
message: Cow::Owned(source.to_string()),
108104
status: StatusCode::INTERNAL_SERVER_ERROR,
109-
})
110-
}
111-
AxumNope::Redirect(target, cache_policy) => {
112-
match super::axum_cached_redirect(&encode_url_path(&target), cache_policy) {
113-
Ok(response) => ErrorResponse::Redirect(response),
114-
// Recurse 1 step:
115-
Err(err) => AxumNope::InternalError(err).into_error_response(),
116105
}
117106
}
107+
AxumNope::Redirect(_target, _cache_policy) => unreachable!(),
118108
}
119109
}
120110
}
121111

122-
// A response representing an outcome from `AxumNope`, usable in both
123-
// HTML or JSON (API) based endpoints.
124-
enum ErrorResponse {
125-
// Info representable both as HTML or as JSON
126-
ErrorInfo(ErrorInfo),
127-
// Redirect,
128-
Redirect(AxumResponse),
129-
// To recreate empty search page; only valid in HTML based
130-
// endpoints.
131-
Search(Search),
132-
}
133-
134112
struct ErrorInfo {
135113
// For the title of the page
136114
pub title: &'static str,
@@ -140,60 +118,40 @@ struct ErrorInfo {
140118
pub status: StatusCode,
141119
}
142120

143-
impl ErrorResponse {
144-
fn into_html_response(self) -> AxumResponse {
145-
match self {
146-
ErrorResponse::ErrorInfo(ErrorInfo {
147-
title,
148-
message,
149-
status,
150-
}) => AxumErrorPage {
151-
title,
152-
message,
153-
status,
154-
}
155-
.into_response(),
156-
ErrorResponse::Redirect(response) => response,
157-
ErrorResponse::Search(search) => search.into_response(),
158-
}
159-
}
160-
161-
fn into_json_response(self) -> AxumResponse {
162-
match self {
163-
ErrorResponse::ErrorInfo(ErrorInfo {
164-
title,
165-
message,
166-
status,
167-
}) => (
168-
status,
169-
Json(serde_json::json!({
170-
"title": title,
171-
"message": message,
172-
})),
173-
)
174-
.into_response(),
175-
ErrorResponse::Redirect(response) => response,
176-
ErrorResponse::Search(search) => {
177-
// FUTURE: this runtime error is avoidable by
178-
// splitting `enum AxumNope` into hierarchical parts,
179-
// see above.
180-
error!(
181-
"expecting that handlers that return JSON error responses \
182-
don't return Search, but got: {search:?}"
183-
);
184-
AxumNope::InternalError(anyhow!(
185-
"bug: search HTML page returned from endpoint that returns JSON"
186-
))
187-
.into_error_response()
188-
.into_json_response()
189-
}
190-
}
121+
fn redirect_with_policy(target: String, cache_policy: CachePolicy) -> AxumResponse {
122+
match super::axum_cached_redirect(&encode_url_path(&target), cache_policy) {
123+
Ok(response) => response.into_response(),
124+
Err(err) => AxumNope::InternalError(err).into_response(),
191125
}
192126
}
193127

194128
impl IntoResponse for AxumNope {
195129
fn into_response(self) -> AxumResponse {
196-
self.into_error_response().into_html_response()
130+
match self {
131+
AxumNope::NoResults => {
132+
// user did a search with no search terms
133+
Search {
134+
title: "No results given for empty search query".to_owned(),
135+
status: StatusCode::NOT_FOUND,
136+
..Default::default()
137+
}
138+
.into_response()
139+
}
140+
AxumNope::Redirect(target, cache_policy) => redirect_with_policy(target, cache_policy),
141+
_ => {
142+
let ErrorInfo {
143+
title,
144+
message,
145+
status,
146+
} = self.into_error_info();
147+
AxumErrorPage {
148+
title,
149+
message,
150+
status,
151+
}
152+
.into_response()
153+
}
154+
}
197155
}
198156
}
199157

@@ -202,7 +160,29 @@ pub(crate) struct JsonAxumNope(pub AxumNope);
202160

203161
impl IntoResponse for JsonAxumNope {
204162
fn into_response(self) -> AxumResponse {
205-
self.0.into_error_response().into_json_response()
163+
match self.0 {
164+
AxumNope::NoResults => {
165+
// user did a search with no search terms; invalid,
166+
// return 404
167+
StatusCode::NOT_FOUND.into_response()
168+
}
169+
AxumNope::Redirect(target, cache_policy) => redirect_with_policy(target, cache_policy),
170+
_ => {
171+
let ErrorInfo {
172+
title,
173+
message,
174+
status,
175+
} = self.0.into_error_info();
176+
(
177+
status,
178+
Json(serde_json::json!({
179+
"title": title,
180+
"message": message,
181+
})),
182+
)
183+
.into_response()
184+
}
185+
}
206186
}
207187
}
208188

0 commit comments

Comments
 (0)