Further centralize state, return result from serial methods

This commit is contained in:
Juno Takano 2026-01-17 04:01:03 -03:00
commit c23d35217d
15 changed files with 471 additions and 244 deletions

View file

@ -1,12 +1,13 @@
use axum::{
body::Body,
http::{Response, StatusCode, header, HeaderValue},
extract::{Path, State},
http::{HeaderValue, Response, StatusCode, header},
};
use crate::prelude::*;
use crate::{
router::handlers,
graph::{Graph, Format},
graph::{Format, Graph, SerialErrorCause},
router::{GlobalState, handlers},
};
/// # Panics
@ -41,22 +42,68 @@ pub async fn file(file_path: &str, content_type: &str) -> Response<Body> {
response
}
#[expect(clippy::unused_async)]
pub async fn serial(format: &Format) -> Response<Body> {
let graph = Graph::load();
let body = Graph::to_serial(&graph, format);
pub async fn serial(
Path(format): Path<String>,
State(state): State<GlobalState>,
) -> Response<Body> {
let config = &state.graph.meta.config;
match *format {
Format::TOML => handlers::raw::make_response(
&body,
200,
&[(header::CONTENT_TYPE, "text/plain")],
),
Format::JSON => handlers::raw::make_response(
&body,
200,
&[(header::CONTENT_TYPE, "application/json")],
),
let make_error = |code: u16, message: &str| -> Response<Body> {
handlers::error::by_code(
Some(code),
Some(
format!(
"<p>{message}</p>\n\
<p>Check the <a href=/data>data</a> \n\
page for the available formats.</p>"
)
.as_str(),
),
&state.graph,
)
};
let forbidden_response =
make_error(403, "This graph format is not available.");
let unsupported_response =
make_error(400, "This graph format is not supported.");
let parse_failure = make_error(505, "The graph has failed to parse.");
let body =
match Graph::to_serial(&state.graph, &Format::from(format.as_str())) {
Ok(serial) => serial,
Err(error) => match error.cause {
SerialErrorCause::MalformedInput => return parse_failure,
SerialErrorCause::UnsupportedFormat => {
return unsupported_response;
},
},
};
match Format::from(format.as_str()) {
Format::TOML => {
if config.raw && config.raw_toml {
handlers::raw::make_response(
&body,
200,
&[(header::CONTENT_TYPE, "text/plain")],
)
} else {
forbidden_response
}
},
Format::JSON => {
if config.raw && config.raw_json {
handlers::raw::make_response(
&body,
200,
&[(header::CONTENT_TYPE, "application/json")],
)
} else {
forbidden_response
}
},
Format::Unsupported => unsupported_response,
}
}
@ -64,15 +111,28 @@ pub async fn serial(format: &Format) -> Response<Body> {
mod tests {
use super::*;
async fn wrap_serial(format: &str) -> Response<Body> {
let state = GlobalState {
graph: Graph::load(),
};
serial(Path(format.to_string()), State(state)).await
}
#[tokio::test]
async fn serial_toml() {
let response = serial(&Format::TOML).await;
let response = wrap_serial("toml").await;
assert!(response.status() == 200);
}
#[tokio::test]
async fn serial_json() {
let response = wrap_serial("json").await;
assert!(response.status() == 200);
}
#[tokio::test]
async fn serial_toml_content_type() {
let response = serial(&Format::TOML).await;
let response = wrap_serial("TOML").await;
assert!(
response.headers().get(header::CONTENT_TYPE).unwrap()
== "text/plain"
@ -81,7 +141,7 @@ mod tests {
#[tokio::test]
async fn serial_json_content_type() {
let response = serial(&Format::JSON).await;
let response = wrap_serial("json").await;
assert!(
response.headers().get(header::CONTENT_TYPE).unwrap()
== "application/json"