Begining of a RON API to edit profile

This commit is contained in:
Greg Burri 2024-11-14 01:59:40 +01:00
parent 37f6de7a89
commit 405aa68526
11 changed files with 229 additions and 68 deletions

View file

@ -0,0 +1,102 @@
use axum::{
async_trait,
body::Bytes,
extract::{FromRequest, Request},
http::{header, StatusCode},
response::{IntoResponse, Response},
};
use ron::{
de::from_bytes,
ser::{to_string_pretty, PrettyConfig},
};
use serde::{de::DeserializeOwned, Serialize};
const RON_CONTENT_TYPE: &'static str = "application/ron";
#[derive(Debug, Serialize, Clone)]
pub struct RonError {
pub error: String,
}
impl axum::response::IntoResponse for RonError {
fn into_response(self) -> Response {
let ron_as_str = to_string_pretty(&self, PrettyConfig::new()).unwrap();
ron_as_str.into_response()
}
}
impl From<RonError> for Response {
fn from(value: RonError) -> Self {
value.into_response()
}
}
pub fn ron_error(status: StatusCode, message: &str) -> impl IntoResponse {
(
status,
[(header::CONTENT_TYPE, RON_CONTENT_TYPE)],
RonError {
error: message.to_string(),
},
)
}
pub fn ron_response<T>(ron: T) -> impl IntoResponse
where
T: Serialize,
{
let ron_as_str = to_string_pretty(&ron, PrettyConfig::new()).unwrap();
([(header::CONTENT_TYPE, RON_CONTENT_TYPE)], ron_as_str)
}
fn parse_body<T>(body: Bytes) -> Result<T, RonError>
where
T: DeserializeOwned,
{
match from_bytes::<T>(&body) {
Ok(ron) => Ok(ron),
Err(error) => {
return Err(RonError {
error: format!("Ron parsing error: {}", error),
});
}
}
}
pub struct ExtractRon<T: DeserializeOwned>(pub T);
#[async_trait]
impl<S, T> FromRequest<S> for ExtractRon<T>
where
S: Send + Sync,
T: DeserializeOwned,
{
type Rejection = Response; // axum::Error::ErrorResponse;
async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
match req.headers().get(header::CONTENT_TYPE) {
Some(content_type) => {
if content_type != RON_CONTENT_TYPE {
return Err(ron_error(
StatusCode::BAD_REQUEST,
&format!("Invalid content type, must be {}", RON_CONTENT_TYPE),
)
.into_response());
}
}
None => {
return Err(
ron_error(StatusCode::BAD_REQUEST, "No content type given").into_response()
)
}
}
let body = Bytes::from_request(req, state)
.await
.map_err(IntoResponse::into_response)?;
let ron = parse_body(body)?;
Ok(Self(ron))
}
}