camel_processor/data_format/
json.rs1use camel_api::body::Body;
2use camel_api::data_format::DataFormat;
3use camel_api::error::CamelError;
4
5pub struct JsonDataFormat;
6
7impl DataFormat for JsonDataFormat {
8 fn name(&self) -> &str {
9 "json"
10 }
11
12 fn marshal(&self, body: Body) -> Result<Body, CamelError> {
13 match body {
14 Body::Json(v) => {
15 let s = serde_json::to_string(&v).map_err(|e| {
16 CamelError::TypeConversionFailed(format!(
17 "cannot marshal Body::Json to text: {e}"
18 ))
19 })?;
20 Ok(Body::Text(s))
21 }
22 Body::Text(_) => Ok(body),
23 Body::Stream(_) => Err(CamelError::TypeConversionFailed(
24 "cannot marshal Body::Stream — add 'stream_cache' or 'convert_body_to' before this step".to_string(),
25 )),
26 Body::Empty | Body::Xml(_) => Err(CamelError::TypeConversionFailed(
27 "JsonDataFormat::marshal only supports Body::Json, Body::Text, and Body::Bytes"
28 .to_string(),
29 )),
30 Body::Bytes(b) => {
31 let v: serde_json::Value = serde_json::from_slice(&b).map_err(|e| {
32 CamelError::TypeConversionFailed(format!(
33 "cannot marshal Body::Bytes as JSON: {e}"
34 ))
35 })?;
36 Ok(Body::Text(serde_json::to_string(&v).map_err(|e| {
37 CamelError::TypeConversionFailed(format!(
38 "cannot serialize JSON value to text: {e}"
39 ))
40 })?))
41 }
42 }
43 }
44
45 fn unmarshal(&self, body: Body) -> Result<Body, CamelError> {
46 match body {
47 Body::Json(_) => Ok(body),
48 Body::Text(s) => {
49 let v = serde_json::from_str(&s).map_err(|e| {
50 CamelError::TypeConversionFailed(format!(
51 "cannot unmarshal Body::Text as JSON: {e}"
52 ))
53 })?;
54 Ok(Body::Json(v))
55 }
56 Body::Bytes(b) => {
57 let v = serde_json::from_slice(&b).map_err(|e| {
58 CamelError::TypeConversionFailed(format!(
59 "cannot unmarshal Body::Bytes as JSON: {e}"
60 ))
61 })?;
62 Ok(Body::Json(v))
63 }
64 Body::Stream(_) => Err(CamelError::TypeConversionFailed(
65 "cannot unmarshal Body::Stream directly — use UnmarshalService which auto-materializes"
66 .to_string(),
67 )),
68 Body::Empty | Body::Xml(_) => Err(CamelError::TypeConversionFailed(
69 "JsonDataFormat::unmarshal only supports Body::Json, Body::Text, and Body::Bytes"
70 .to_string(),
71 )),
72 }
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use bytes::Bytes;
80 use serde_json::json;
81
82 #[test]
83 fn test_name() {
84 assert_eq!(JsonDataFormat.name(), "json");
85 }
86
87 #[test]
88 fn test_unmarshal_text_to_json() {
89 let body = Body::Text(r#"{"a":1}"#.to_string());
90 let result = JsonDataFormat.unmarshal(body).unwrap();
91 assert!(matches!(result, Body::Json(_)));
92 if let Body::Json(v) = result {
93 assert_eq!(v["a"], json!(1));
94 }
95 }
96
97 #[test]
98 fn test_unmarshal_bytes_to_json() {
99 let body = Body::Bytes(Bytes::from_static(b"{\"b\":2}"));
100 let result = JsonDataFormat.unmarshal(body).unwrap();
101 assert!(matches!(result, Body::Json(_)));
102 }
103
104 #[test]
105 fn test_unmarshal_invalid_json() {
106 let body = Body::Text("not json".to_string());
107 let result = JsonDataFormat.unmarshal(body);
108 assert!(matches!(result, Err(CamelError::TypeConversionFailed(_))));
109 }
110
111 #[test]
112 fn test_unmarshal_json_noop() {
113 let body = Body::Json(json!({"x": 1}));
114 let result = JsonDataFormat.unmarshal(body).unwrap();
115 assert!(matches!(result, Body::Json(_)));
116 }
117
118 #[test]
119 fn test_unmarshal_unsupported_variant() {
120 let body = Body::Empty;
121 let result = JsonDataFormat.unmarshal(body);
122 assert!(matches!(result, Err(CamelError::TypeConversionFailed(_))));
123 }
124
125 #[test]
126 fn test_unmarshal_stream_rejected() {
127 use camel_api::body::{StreamBody, StreamMetadata};
128 use futures::stream;
129 use std::sync::Arc;
130 use tokio::sync::Mutex;
131
132 let stream = stream::iter(vec![Ok(Bytes::from_static(b"data"))]);
133 let body = Body::Stream(StreamBody {
134 stream: Arc::new(Mutex::new(Some(Box::pin(stream)))),
135 metadata: StreamMetadata::default(),
136 });
137 let result = JsonDataFormat.unmarshal(body);
138 assert!(matches!(result, Err(CamelError::TypeConversionFailed(_))));
139 }
140
141 #[test]
142 fn test_marshal_json_to_text() {
143 let body = Body::Json(json!({"key": "value"}));
144 let result = JsonDataFormat.marshal(body).unwrap();
145 match result {
146 Body::Text(s) => assert!(s.contains("\"key\"")),
147 _ => panic!("expected Body::Text"),
148 }
149 }
150
151 #[test]
152 fn test_marshal_text_noop() {
153 let body = Body::Text("already text".to_string());
154 let result = JsonDataFormat.marshal(body).unwrap();
155 assert_eq!(result, Body::Text("already text".to_string()));
156 }
157
158 #[test]
159 fn test_marshal_unsupported_variant() {
160 let body = Body::Xml("<root/>".to_string());
161 let result = JsonDataFormat.marshal(body);
162 assert!(matches!(result, Err(CamelError::TypeConversionFailed(_))));
163 }
164
165 #[test]
166 fn test_marshal_bytes_to_text() {
167 let body = Body::Bytes(Bytes::from_static(b"{\"key\":\"val\"}"));
168 let result = JsonDataFormat.marshal(body).unwrap();
169 match result {
170 Body::Text(s) => assert!(s.contains("\"key\"")),
171 _ => panic!("expected Body::Text"),
172 }
173 }
174
175 #[test]
176 fn test_marshal_invalid_bytes_returns_error() {
177 let body = Body::Bytes(Bytes::from_static(b"not json"));
178 let result = JsonDataFormat.marshal(body);
179 assert!(matches!(result, Err(CamelError::TypeConversionFailed(_))));
180 }
181}