pub struct HttpError {
pub http_status_code: StatusCode,
pub public: Box<dyn DynSerialize + Send + Sync>,
pub context: Option<String>,
}
Expand description
Self-sufficient container to both log an error and generate its HTTP response.
Error implements From<HttpError>
, use ?
and .into()
in functions and closures to convert to the Error::Domain variant.
Note: HttpError convert to Error by converting first to DomainError.
§Examples
Domain errors that derive HttpError must implement From<&MyDomainError> for HttpError
.
use explicit_error_http::{derive::HttpError, prelude::*, HttpError};
#[derive(HttpError, Debug)]
enum MyDomainError {
Foo,
}
impl From<&MyDomainError> for HttpError {
fn from(value: &MyDomainError) -> Self {
match value {
MyDomainError::Foo => HttpError::new(
StatusCode::BAD_REQUEST,
ProblemDetails::new()
.with_type(Uri::from_static("/errors/my-domain/foo"))
.with_title("Foo format incorrect.")
),
}
}
}
Domain errors cannot require to be extracted in either a struct or enum variant (eg: middleware errors). You can generate Error::Domain variant with an HttpError
use explicit_error_http::{Error, prelude::*, HttpError};
fn business_logic() -> Result<(), Error> {
Err(HttpError::new(
StatusCode::FORBIDDEN,
ProblemDetails::new()
.with_type(Uri::from_static("/errors/generic#forbidden"))
.with_title("Forbidden."),
))?;
}
Usually to avoid boilerplate and having consistency in error responses web applications implement helpers for frequent http error codes.
use explicit_error_http::{prelude::*, HttpError, Error};
fn forbidden() -> HttpError {
HttpError::new(
StatusCode::FORBIDDEN,
ProblemDetails::new()
.with_type(Uri::from_static("/errors/generic#forbidden"))
.with_title("Forbidden."),
)
}
// context can be added by the caller to add information in log
fn business_logic() -> Result<(), Error> {
Err(42).map_err(|e|
forbidden().with_context(
format!("Return a forbidden instead of 500 to avoid leaking implementation details: {e}")
))?;
}
Fields§
§http_status_code: StatusCode
§public: Box<dyn DynSerialize + Send + Sync>
§context: Option<String>
Implementations§
Source§impl HttpError
impl HttpError
Sourcepub fn new<S: Serialize + 'static + Send + Sync>(
http_status_code: StatusCode,
public: S,
) -> Self
pub fn new<S: Serialize + 'static + Send + Sync>( http_status_code: StatusCode, public: S, ) -> Self
Generate an HttpError without a context. To add a context use with_context afterwards.
§Examples
fn forbidden() -> HttpError {
HttpError::new(
StatusCode::UNAUTHORIZED,
ProblemDetails::new()
.with_type(Uri::from_static("/errors/forbidden"))
.with_title("Forbidden"),
)
}
Sourcepub fn with_context(self, context: impl Display) -> Self
pub fn with_context(self, context: impl Display) -> Self
Add a context to an HttpError, override if one was set. The context appears in display but not in the http response.
§Examples
fn check_authz() -> Result<()> {
if !false {
Err(forbidden().with_context("Some info to help debug"))?;
}
Ok(())
}
fn forbidden() -> HttpError {
HttpError::new(
StatusCode::UNAUTHORIZED,
ProblemDetails::new()
.with_type(Uri::from_static("/errors/forbidden"))
.with_title("Forbidden"),
)
}
Sourcepub fn with_source<E: Error + 'static + Send + Sync>(
self,
error: E,
) -> DomainError
pub fn with_source<E: Error + 'static + Send + Sync>( self, error: E, ) -> DomainError
Add a source to an HttpError by converting it on the fly to a crate::DomainError
§Example
fn check() -> Result<()> {
Err(sqlx::Error::RowNotFound).map_err(|e|
HttpError::new(StatusCode::NOT_FOUND, "not found")
.with_source(e))?;
}