use std::collections::HashMap;
use hyper::{HeaderMap, StatusCode};
use serde_json::Value;
use crate::{
response::error_response::internal_server_error_response, response_handler::ResponseHandler,
types::BoxBody,
};
pub fn json_response(
json_str: &str,
status_code: Option<&StatusCode>,
custom_headers: Option<&HashMap<String, Option<String>>>,
request_headers: &HeaderMap,
source: Option<&str>,
cors_allow_credentials_origins: &[String],
) -> Result<hyper::Response<BoxBody>, hyper::http::Error> {
match json5::from_str::<Value>(json_str) {
Ok(content) => {
let body = content.to_string();
let mut response_handler = ResponseHandler::default().with_json_body(body.as_str());
if let Some(status_code) = status_code {
response_handler = response_handler.with_status(status_code);
}
response_handler
.with_custom_headers(custom_headers)
.into_response(request_headers, cors_allow_credentials_origins)
}
Err(err) => {
log::error!(
"invalid json content{}: {}",
source.map(|s| format!(" ({})", s)).unwrap_or_default(),
err
);
internal_server_error_response(
"invalid json content",
request_headers,
cors_allow_credentials_origins,
)
}
}
}
#[cfg(test)]
mod tests {
use hyper::HeaderMap;
use super::json_response;
#[tokio::test]
async fn key_order_survives_the_parse_and_reserialise_round_trip() {
let response = json_response(
r#"{"zebra":1,"apple":2}"#,
None,
None,
&HeaderMap::new(),
None,
&[],
)
.unwrap();
assert_eq!(response.status(), hyper::StatusCode::OK);
let body = http_body_util::BodyExt::collect(response.into_body())
.await
.unwrap()
.to_bytes();
assert_eq!(
body.as_ref(),
br#"{"zebra":1,"apple":2}"#,
"key order must survive the round trip, not be alphabetised"
);
}
}