Error handling refactor and 500 page/message templates
This commit is contained in:
@@ -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)?;
|
||||
|
||||
Reference in New Issue
Block a user