staxman-old/src/http/response.rs

89 lines
2.2 KiB
Rust

use super::{
accept::{parse_accept, ResponseType},
error::{ErrorInfo, Result},
};
use askama::Template;
use askama_axum::IntoResponse;
use axum::{
http::{header::ACCEPT, Request, StatusCode},
middleware::Next,
response::Html,
Json,
};
use serde_json::json;
pub type HandlerResponse = Result<askama_axum::Response>;
struct Response {
html: String,
json: serde_json::Value,
}
#[derive(Template)]
#[template(path = "error.html")]
struct ErrorTemplate {
status: String,
message: String,
}
pub fn reply<T: Template>(json: serde_json::Value, html: T) -> HandlerResponse {
let mut response = StatusCode::OK.into_response();
response.extensions_mut().insert(Response {
html: html.render()?,
json,
});
Ok(response)
}
/// Handles the multiple return type system of staxman.
/// Handlers might return an Error or a Response object, this will intercept
/// those and return them as either JSON or HTML depending on the Accept header.
pub async fn response_interceptor<B>(
request: Request<B>,
next: Next<B>,
) -> axum::response::Response {
let accept = request
.headers()
.get(&ACCEPT)
.map(parse_accept)
.unwrap_or_else(|| ResponseType::Html);
let mut response = next.run(request).await;
if let Some(ErrorInfo {
status,
code,
message,
}) = response.extensions_mut().remove::<ErrorInfo>()
{
match accept {
ResponseType::Json => {
return (status, Json(json!({"code": code, "message": message}))).into_response();
}
_ => {
return (
status,
ErrorTemplate {
status: status.to_string(),
message,
},
)
.into_response();
}
}
}
if let Some(Response { html, json }) = response.extensions_mut().remove::<Response>() {
match accept {
ResponseType::Json => {
return Json(json).into_response();
}
_ => {
return Html(html).into_response();
}
}
}
response
}