custom extractors rejection
Some checks failed
Rust / Test (push) Has been cancelled
Rust / Rustfmt (push) Has been cancelled
Rust / Clippy (push) Has been cancelled
Rust / Code coverage (push) Has been cancelled

This commit is contained in:
Alphonse Paix
2025-09-27 02:28:04 +02:00
parent f9ae3f42a6
commit f43e143bf6
6 changed files with 68 additions and 13 deletions

View File

@@ -10,7 +10,8 @@ mod unsubscribe;
pub use admin::*;
use askama::Template;
use axum::{
http::HeaderMap,
extract::FromRequestParts,
http::{HeaderMap, request::Parts},
response::{Html, IntoResponse, Response},
};
pub use health_check::*;
@@ -19,6 +20,7 @@ pub use login::*;
pub use posts::*;
use rand::{Rng, distr::Alphanumeric};
use reqwest::StatusCode;
use serde::de::DeserializeOwned;
pub use subscriptions::*;
pub use subscriptions_confirm::*;
pub use unsubscribe::*;
@@ -61,6 +63,8 @@ pub enum AppError {
FormError(#[source] anyhow::Error),
#[error("Authentication is required.")]
NotAuthenticated,
#[error("Handler extractor failed.")]
Extractor(#[source] anyhow::Error),
}
impl From<anyhow::Error> for AppError {
@@ -124,6 +128,7 @@ impl IntoResponse for AppError {
headers.insert("HX-Redirect", "/login".parse().unwrap());
(StatusCode::OK, headers).into_response()
}
AppError::Extractor(_) => not_found_html(),
}
}
}
@@ -155,6 +160,50 @@ impl From<AuthError> for AppError {
}
pub async fn not_found() -> Response {
let template = HtmlTemplate(NotFoundTemplate);
(StatusCode::NOT_FOUND, template).into_response()
(StatusCode::NOT_FOUND, not_found_html()).into_response()
}
pub fn not_found_html() -> Response {
let template = HtmlTemplate(NotFoundTemplate);
template.into_response()
}
pub struct Path<T>(T);
impl<T, S> FromRequestParts<S> for Path<T>
where
T: DeserializeOwned + Send,
S: Send + Sync,
{
type Rejection = AppError;
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
match axum::extract::Path::<T>::from_request_parts(parts, state).await {
Ok(value) => Ok(Self(value.0)),
Err(rejection) => Err(AppError::Extractor(anyhow::anyhow!(
"Path rejection: {:?}",
rejection
))),
}
}
}
pub struct Query<T>(pub T);
impl<T, S> FromRequestParts<S> for Query<T>
where
T: DeserializeOwned,
S: Send + Sync,
{
type Rejection = AppError;
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
match axum::extract::Query::<T>::from_request_parts(parts, state).await {
Ok(value) => Ok(Self(value.0)),
Err(rejection) => Err(AppError::Extractor(anyhow::anyhow!(
"Query rejection: {:?}",
rejection
))),
}
}
}

View File

@@ -1,7 +1,9 @@
use crate::{
authentication::AuthenticatedUser,
idempotency::{IdempotencyKey, save_response, try_processing},
routes::{AdminError, AppError, EmailType, enqueue_delivery_tasks, insert_newsletter_issue},
routes::{
AdminError, AppError, EmailType, Path, enqueue_delivery_tasks, insert_newsletter_issue,
},
startup::AppState,
templates::{MessageTemplate, NewPostEmailTemplate},
};
@@ -9,7 +11,7 @@ use anyhow::Context;
use askama::Template;
use axum::{
Extension, Form,
extract::{Path, State},
extract::State,
response::{Html, IntoResponse, Response},
};
use chrono::Utc;

View File

@@ -1,13 +1,13 @@
use crate::{
domain::SubscriberEntry,
routes::AppError,
routes::{AppError, Path, Query},
startup::AppState,
templates::{MessageTemplate, SubListTemplate},
};
use anyhow::Context;
use askama::Template;
use axum::{
extract::{Path, Query, State},
extract::State,
response::{Html, IntoResponse, Response},
};
use sqlx::PgPool;

View File

@@ -1,13 +1,13 @@
use crate::{
domain::PostEntry,
routes::{AppError, not_found},
routes::{AppError, Path, Query, not_found_html},
startup::AppState,
templates::{HtmlTemplate, PostListTemplate, PostTemplate, PostsTemplate},
};
use anyhow::Context;
use askama::Template;
use axum::{
extract::{Path, Query, State},
extract::State,
response::{Html, IntoResponse, Redirect, Response},
};
use sqlx::PgPool;
@@ -90,7 +90,7 @@ pub async fn see_post(
let template = HtmlTemplate(PostTemplate { post });
Ok(template.into_response())
} else {
Ok(not_found().await)
Ok(not_found_html())
}
}

View File

@@ -1,7 +1,11 @@
use crate::{routes::generate_token, startup::AppState, templates::ConfirmTemplate};
use crate::{
routes::{Query, generate_token},
startup::AppState,
templates::ConfirmTemplate,
};
use askama::Template;
use axum::{
extract::{Query, State},
extract::State,
http::StatusCode,
response::{Html, IntoResponse, Response},
};