You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
inventory-app/src/util/extract/validated_form.rs

82 lines
2.3 KiB

use std::ops::{Deref, DerefMut};
use axum::extract::{FromRequest, FromRequestParts, Request};
use axum::http::StatusCode;
use axum::{async_trait, RequestPartsExt};
use axum::extract::rejection::FormRejection;
use axum::response::{IntoResponse, IntoResponseParts};
use crate::app::routes::AppState;
use crate::error::AppError;
use super::htmx_form_data::{HtmxFormData, HtmxFormDataError};
#[derive(Debug, Clone, Copy, Default)]
pub struct ValidatedForm<T>(pub T);
#[async_trait]
impl<T> FromRequest<AppState> for ValidatedForm<T>
where
T: HtmxFormData
{
type Rejection = ValidatedFormError<T::FormTemplate>;
async fn from_request(req: Request, state: &AppState) -> Result<Self, Self::Rejection> {
let raw_form_data = axum::Form::<T>::from_request(req, state)
.await
.map_err(|e| ValidatedFormError::FormError(e))?;
let value = raw_form_data.0
.validate(&state)
.await
.map_err(|e|
match e {
HtmxFormDataError::ValidationError(e) => ValidatedFormError::ValidationError(e),
HtmxFormDataError::InternalServerError(e) => ValidatedFormError::InternalServerError(e),
}
)?;
Ok(ValidatedForm(value))
}
}
impl<T> Deref for ValidatedForm<T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for ValidatedForm<T> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
pub enum ValidatedFormError<T> {
ValidationError(T),
FormError(FormRejection),
InternalServerError(anyhow::Error)
}
impl<T> IntoResponse for ValidatedFormError<T>
where T: IntoResponse
{
fn into_response(self) -> axum::response::Response {
match self {
ValidatedFormError::FormError(err) => {
err.into_response()
},
ValidatedFormError::ValidationError(err) => {
let (mut parts, body) = err.into_response().into_parts();
parts.status = StatusCode::OK;
(parts, body).into_response()
}
ValidatedFormError::InternalServerError(err) => {
AppError::from(err).into_response()
}
}
}
}

Powered by TurnKey Linux.