cratestack_axum/transport/
encode_sequence.rs1use axum::http::{HeaderMap, StatusCode};
2use axum::response::Response;
3use cratestack_core::{CratestackError, RouteTransportCapabilities};
4use futures_util::{Stream, TryStreamExt};
5use serde::Serialize;
6
7use super::CBOR_SEQUENCE_CONTENT_TYPE;
8use super::http_transport::HttpTransport;
9use super::internal::fallback_error_response;
10use super::media_type::select_transport_response_content_type;
11
12pub fn encode_transport_sequence_result<TTransport, TValue>(
13 transport: &TTransport,
14 headers: &HeaderMap,
15 result: Result<Vec<TValue>, CratestackError>,
16) -> Response
17where
18 TTransport: HttpTransport,
19 TValue: Serialize,
20{
21 encode_transport_sequence_result_with_status_for(
22 transport,
23 headers,
24 &RouteTransportCapabilities {
25 request_types: &[],
26 response_types: &[],
27 default_response_type: "",
28 supports_sequence_response: false,
29 },
30 StatusCode::OK,
31 result,
32 )
33}
34
35pub fn encode_transport_sequence_result_with_status<TTransport, TValue>(
36 transport: &TTransport,
37 headers: &HeaderMap,
38 success_status: StatusCode,
39 result: Result<Vec<TValue>, CratestackError>,
40) -> Response
41where
42 TTransport: HttpTransport,
43 TValue: Serialize,
44{
45 encode_transport_sequence_result_with_status_for(
46 transport,
47 headers,
48 &RouteTransportCapabilities {
49 request_types: &[],
50 response_types: &[],
51 default_response_type: "",
52 supports_sequence_response: false,
53 },
54 success_status,
55 result,
56 )
57}
58
59pub fn encode_transport_sequence_result_with_status_for<TTransport, TValue>(
60 transport: &TTransport,
61 headers: &HeaderMap,
62 capabilities: &RouteTransportCapabilities,
63 success_status: StatusCode,
64 result: Result<Vec<TValue>, CratestackError>,
65) -> Response
66where
67 TTransport: HttpTransport,
68 TValue: Serialize,
69{
70 if !capabilities.supports_sequence_response {
71 return fallback_error_response(CratestackError::Internal(
72 "sequence response encoding requested for a route without sequence capability"
73 .to_owned(),
74 ));
75 }
76 let content_type =
77 match select_transport_response_content_type(transport, headers, capabilities) {
78 Ok(content_type) => content_type,
79 Err(error) => return fallback_error_response(error),
80 };
81 match result {
82 Ok(values) => transport
83 .encode_sequence_response(content_type, success_status, &values)
84 .unwrap_or_else(fallback_error_response),
85 Err(error) => {
86 let status = error.status_code();
87 let body = error.into_response();
88 transport
89 .encode_sequence_error_response(content_type, status, &body)
90 .unwrap_or_else(fallback_error_response)
91 }
92 }
93}
94
95pub async fn encode_transport_stream_result_with_status_for<TTransport, TValue, S>(
115 transport: &TTransport,
116 headers: &HeaderMap,
117 capabilities: &RouteTransportCapabilities,
118 success_status: StatusCode,
119 result: Result<S, CratestackError>,
120) -> Response
121where
122 TTransport: HttpTransport,
123 TValue: Serialize + Send + 'static,
124 S: Stream<Item = Result<TValue, CratestackError>> + Send + 'static,
125{
126 if !capabilities.supports_sequence_response {
127 return fallback_error_response(CratestackError::Internal(
128 "sequence response encoding requested for a route without sequence capability"
129 .to_owned(),
130 ));
131 }
132 let content_type =
133 match select_transport_response_content_type(transport, headers, capabilities) {
134 Ok(content_type) => content_type,
135 Err(error) => return fallback_error_response(error),
136 };
137 match result {
138 Ok(stream) => {
139 if content_type == CBOR_SEQUENCE_CONTENT_TYPE {
140 transport
141 .encode_sequence_stream_response(content_type, success_status, stream)
142 .unwrap_or_else(fallback_error_response)
143 } else {
144 let values: Result<Vec<TValue>, CratestackError> = stream.try_collect().await;
145 encode_transport_sequence_result_with_status_for(
146 transport,
147 headers,
148 capabilities,
149 success_status,
150 values,
151 )
152 }
153 }
154 Err(error) => {
155 let status = error.status_code();
156 let body = error.into_response();
157 transport
158 .encode_sequence_error_response(content_type, status, &body)
159 .unwrap_or_else(fallback_error_response)
160 }
161 }
162}
163
164#[cfg(test)]
165mod tests;