Skip to content

Commit 5a324a1

Browse files
authored
Merge pull request #5 from fpco/control-status-code
Allow controlling status code of error responses.
2 parents 4be6857 + 2d8ef15 commit 5a324a1

File tree

1 file changed

+34
-7
lines changed

1 file changed

+34
-7
lines changed

src/lib.rs

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::{
22
collections::HashMap,
3-
fmt::Debug,
3+
fmt::{Debug, Display},
44
sync::Arc,
55
time::{Duration, Instant},
66
};
@@ -168,11 +168,30 @@ pub enum ValueForRender<Loader: CacheLoader> {
168168
/// Error while loading the value
169169
Error {
170170
message: Arc<str>,
171+
status: StatusCode,
171172
/// If there's a cached value available that's considered stale, provide it here.
172173
stale_cache: Option<Latest<Loader>>,
173174
},
174175
}
175176

177+
/// An error type that wraps up a [axum::Response].
178+
///
179+
/// If you return this as an error value from [CacheLoader::load],
180+
/// it will be used as the error response.
181+
#[derive(Clone, Debug)]
182+
pub struct ErrorResponse {
183+
pub status: StatusCode,
184+
pub message: String,
185+
}
186+
187+
impl std::error::Error for ErrorResponse {}
188+
189+
impl Display for ErrorResponse {
190+
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
191+
f.write_str(&self.message)
192+
}
193+
}
194+
176195
impl<Loader: CacheLoader> Clone for ValueForRender<Loader> {
177196
fn clone(&self) -> Self {
178197
match self {
@@ -182,9 +201,11 @@ impl<Loader: CacheLoader> Clone for ValueForRender<Loader> {
182201
},
183202
ValueForRender::Error {
184203
message,
204+
status,
185205
stale_cache,
186206
} => ValueForRender::Error {
187207
message: message.clone(),
208+
status: *status,
188209
stale_cache: stale_cache.clone(),
189210
},
190211
}
@@ -210,12 +231,9 @@ impl<Loader: CacheLoader> ValueForRender<Loader> {
210231
}
211232
ValueForRender::Error {
212233
message,
234+
status,
213235
stale_cache: _,
214-
} => {
215-
let mut res = message.as_ref().to_owned().into_response();
216-
*res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
217-
res
218-
}
236+
} => (status, message.as_ref().to_owned()).into_response(),
219237
}
220238
}
221239
}
@@ -336,6 +354,7 @@ impl<Loader: CacheLoader> AsyncLoader<Loader> {
336354
tracing::error!("AsyncLoader::get_response: impossible Err received: {err:?}");
337355
ValueForRender::Error {
338356
message: "Internal error detected: broadcast channel is gone".into(),
357+
status: StatusCode::INTERNAL_SERVER_ERROR,
339358
stale_cache,
340359
}
341360
}
@@ -369,6 +388,7 @@ impl<Loader: CacheLoader> AsyncLoader<Loader> {
369388
tracing::error!("AsyncLoader::get_response: impossible Err received: {err:?}");
370389
ValueForRender::Error {
371390
message: "Internal error detected: broadcast channel is gone".into(),
391+
status: StatusCode::INTERNAL_SERVER_ERROR,
372392
stale_cache,
373393
}
374394
}
@@ -410,6 +430,7 @@ impl<Loader: CacheLoader> AsyncLoader<Loader> {
410430
ValueForRender::Success { value, loaded: _ } => Ok(value),
411431
ValueForRender::Error {
412432
message,
433+
status: _,
413434
stale_cache,
414435
} => match stale_cache {
415436
Some(latest) => Ok(latest.value),
@@ -490,6 +511,7 @@ impl<Loader: CacheLoader> AsyncLoader<Loader> {
490511
}),
491512
ValueForRender::Error {
492513
message: _,
514+
status: _,
493515
stale_cache,
494516
} => stale_cache.clone(),
495517
};
@@ -571,8 +593,13 @@ impl<Loader: CacheLoader> AsyncLoader<Loader> {
571593
},
572594
Err(err) => {
573595
tracing::error!("AsyncLoader::do_update: {err:?}");
596+
let (message, status) = match err.downcast() {
597+
Ok(ErrorResponse { status, message }) => (message, status),
598+
Err(err) => (err.to_string(), StatusCode::INTERNAL_SERVER_ERROR),
599+
};
574600
ValueForRender::Error {
575-
message: err.to_string().into(),
601+
message: message.into(),
602+
status,
576603
stale_cache,
577604
}
578605
}

0 commit comments

Comments
 (0)