Error handling refactor and 500 page/message templates

This commit is contained in:
Alphonse Paix
2025-09-20 04:06:48 +02:00
parent 7971095227
commit d85879a004
14 changed files with 223 additions and 201 deletions

View File

@@ -1,15 +1,15 @@
use crate::{
domain::{NewSubscriber, SubscriberEmail},
email_client::EmailClient,
routes::AppError,
startup::AppState,
templates::MessageTemplate,
};
use anyhow::Context;
use askama::Template;
use axum::{
Form, Json,
Form,
extract::State,
http::StatusCode,
response::{Html, IntoResponse, Response},
};
use chrono::Utc;
@@ -42,45 +42,6 @@ pub fn error_chain_fmt(
Ok(())
}
#[derive(thiserror::Error)]
pub enum SubscribeError {
#[error(transparent)]
UnexpectedError(#[from] anyhow::Error),
#[error("{0}")]
ValidationError(String),
}
impl std::fmt::Debug for SubscribeError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
error_chain_fmt(self, f)
}
}
impl IntoResponse for SubscribeError {
fn into_response(self) -> Response {
#[derive(serde::Serialize)]
struct ErrorResponse<'a> {
message: &'a str,
}
tracing::error!("{:?}", self);
match self {
SubscribeError::UnexpectedError(_) => (
StatusCode::INTERNAL_SERVER_ERROR,
Json(ErrorResponse {
message: "An internal server error occured.",
}),
)
.into_response(),
SubscribeError::ValidationError(e) => {
let template = MessageTemplate::Error { message: e };
Html(template.render().unwrap()).into_response()
}
}
}
}
#[tracing::instrument(
name = "Adding a new subscriber",
skip(connection_pool, email_client, base_url, form),
@@ -96,13 +57,11 @@ pub async fn subscribe(
..
}): State<AppState>,
Form(form): Form<SubscriptionFormData>,
) -> Result<Response, SubscribeError> {
let new_subscriber = match form.try_into() {
Ok(new_sub) => new_sub,
Err(e) => {
return Err(SubscribeError::ValidationError(e));
}
};
) -> Result<Response, AppError> {
let new_subscriber = form
.try_into()
.context("Failed to parse subscription form data.")
.map_err(AppError::FormError)?;
let mut transaction = connection_pool
.begin()
.await
@@ -122,6 +81,7 @@ pub async fn subscribe(
)
.await
.context("Failed to send a confirmation email.")?;
transaction
.commit()
.await
@@ -214,7 +174,7 @@ pub struct SubscriptionFormData {
}
impl TryFrom<SubscriptionFormData> for NewSubscriber {
type Error = String;
type Error = anyhow::Error;
fn try_from(value: SubscriptionFormData) -> Result<Self, Self::Error> {
let email = SubscriberEmail::parse(value.email)?;