Skip to main content

cratestack_axum/transport/
encode_unary.rs

1use axum::http::{HeaderMap, StatusCode};
2use axum::response::Response;
3use cratestack_core::{CratestackError, RouteTransportCapabilities};
4use serde::Serialize;
5
6use super::http_transport::HttpTransport;
7use super::internal::fallback_error_response;
8use super::media_type::select_transport_response_content_type;
9
10pub fn encode_transport_result<TTransport, TValue>(
11    transport: &TTransport,
12    headers: &HeaderMap,
13    result: Result<TValue, CratestackError>,
14) -> Response
15where
16    TTransport: HttpTransport,
17    TValue: Serialize,
18{
19    encode_transport_result_with_status_for(
20        transport,
21        headers,
22        &RouteTransportCapabilities {
23            request_types: &[],
24            response_types: &[],
25            default_response_type: "",
26            supports_sequence_response: false,
27        },
28        StatusCode::OK,
29        result,
30    )
31}
32
33pub fn encode_transport_result_with_status<TTransport, TValue>(
34    transport: &TTransport,
35    headers: &HeaderMap,
36    success_status: StatusCode,
37    result: Result<TValue, CratestackError>,
38) -> Response
39where
40    TTransport: HttpTransport,
41    TValue: Serialize,
42{
43    encode_transport_result_with_status_for(
44        transport,
45        headers,
46        &RouteTransportCapabilities {
47            request_types: &[],
48            response_types: &[],
49            default_response_type: "",
50            supports_sequence_response: false,
51        },
52        success_status,
53        result,
54    )
55}
56
57pub fn encode_transport_result_with_status_for<TTransport, TValue>(
58    transport: &TTransport,
59    headers: &HeaderMap,
60    capabilities: &RouteTransportCapabilities,
61    success_status: StatusCode,
62    result: Result<TValue, CratestackError>,
63) -> Response
64where
65    TTransport: HttpTransport,
66    TValue: Serialize,
67{
68    let content_type =
69        match select_transport_response_content_type(transport, headers, capabilities) {
70            Ok(content_type) => content_type,
71            Err(error) => return fallback_error_response(error),
72        };
73    match result {
74        Ok(value) => transport
75            .encode_response(content_type, success_status, &value)
76            .unwrap_or_else(fallback_error_response),
77        Err(error) => {
78            let (error, tag) = crate::idempotency::answered(error);
79            let status = error.status_code();
80            let challenges = crate::auth_challenge::challenges_of(&error);
81            let body = error.into_response();
82            let response = transport
83                .encode_response(content_type, status, &body)
84                .unwrap_or_else(fallback_error_response);
85            let response = crate::auth_challenge::attach(response, &challenges);
86            crate::idempotency::with_tag(tag, response)
87        }
88    }
89}
90
91#[cfg(test)]
92mod tests;