api_tools/server/axum/layers/
mod.rs

1//! Axum layers
2
3pub mod basic_auth;
4pub mod cors;
5pub mod http_errors;
6pub mod logger;
7#[cfg(feature = "prometheus")]
8pub mod prometheus;
9pub mod request_id;
10pub mod security_headers;
11pub mod time_limiter;
12
13use crate::server::axum::response::ApiErrorResponse;
14use axum::http::header::CONTENT_TYPE;
15use axum::http::response::Parts;
16use axum::http::{HeaderName, HeaderValue, StatusCode};
17use bytes::Bytes;
18use std::str::from_utf8;
19
20/// Construct a response body from `Parts`, status code, message and headers
21pub fn body_from_parts(
22    parts: &mut Parts,
23    status_code: StatusCode,
24    message: &str,
25    headers: Option<Vec<(HeaderName, HeaderValue)>>,
26) -> Bytes {
27    // Status
28    parts.status = status_code;
29
30    // Headers
31    parts
32        .headers
33        .insert(CONTENT_TYPE, HeaderValue::from_static(mime::APPLICATION_JSON.as_ref()));
34    if let Some(headers) = headers {
35        for header in headers {
36            parts.headers.insert(header.0, header.1);
37        }
38    }
39
40    // Body
41    let msg = serde_json::json!(ApiErrorResponse::new(status_code, message));
42
43    Bytes::from(msg.to_string())
44}
45
46/// Convert `HeaderValue` to `&str`
47pub fn header_value_to_str(value: Option<&HeaderValue>) -> &str {
48    match value {
49        Some(value) => from_utf8(value.as_bytes()).unwrap_or_default(),
50        None => "",
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57
58    #[test]
59    fn test_header_value_to_str() {
60        let header_value = HeaderValue::from_static("test_value");
61        let result = header_value_to_str(Some(&header_value));
62        assert_eq!(result, "test_value");
63
64        let none_result = header_value_to_str(None);
65        assert_eq!(none_result, "");
66    }
67}