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 — materialize with into_bytes() first".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 — materialize with into_bytes() first".to_string(),
66 )),
67 Body::Empty | Body::Xml(_) => Err(CamelError::TypeConversionFailed(
68 "JsonDataFormat::unmarshal only supports Body::Json, Body::Text, and Body::Bytes"
69 .to_string(),
70 )),
71 }
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78 use bytes::Bytes;
79 use serde_json::json;
80
81 #[test]
82 fn test_name() {
83 assert_eq!(JsonDataFormat.name(), "json");
84 }
85
86 #[test]
87 fn test_unmarshal_text_to_json() {
88 let body = Body::Text(r#"{"a":1}"#.to_string());
89 let result = JsonDataFormat.unmarshal(body).unwrap();
90 assert!(matches!(result, Body::Json(_)));
91 if let Body::Json(v) = result {
92 assert_eq!(v["a"], json!(1));
93 }
94 }
95
96 #[test]
97 fn test_unmarshal_bytes_to_json() {
98 let body = Body::Bytes(Bytes::from_static(b"{\"b\":2}"));
99 let result = JsonDataFormat.unmarshal(body).unwrap();
100 assert!(matches!(result, Body::Json(_)));
101 }
102
103 #[test]
104 fn test_unmarshal_invalid_json() {
105 let body = Body::Text("not json".to_string());
106 let result = JsonDataFormat.unmarshal(body);
107 assert!(matches!(result, Err(CamelError::TypeConversionFailed(_))));
108 }
109
110 #[test]
111 fn test_unmarshal_json_noop() {
112 let body = Body::Json(json!({"x": 1}));
113 let result = JsonDataFormat.unmarshal(body).unwrap();
114 assert!(matches!(result, Body::Json(_)));
115 }
116
117 #[test]
118 fn test_unmarshal_unsupported_variant() {
119 let body = Body::Empty;
120 let result = JsonDataFormat.unmarshal(body);
121 assert!(matches!(result, Err(CamelError::TypeConversionFailed(_))));
122 }
123
124 #[test]
125 fn test_unmarshal_stream_rejected() {
126 use camel_api::body::{StreamBody, StreamMetadata};
127 use futures::stream;
128 use std::sync::Arc;
129 use tokio::sync::Mutex;
130
131 let stream = stream::iter(vec![Ok(Bytes::from_static(b"data"))]);
132 let body = Body::Stream(StreamBody {
133 stream: Arc::new(Mutex::new(Some(Box::pin(stream)))),
134 metadata: StreamMetadata::default(),
135 });
136 let result = JsonDataFormat.unmarshal(body);
137 assert!(matches!(result, Err(CamelError::TypeConversionFailed(_))));
138 }
139
140 #[test]
141 fn test_marshal_json_to_text() {
142 let body = Body::Json(json!({"key": "value"}));
143 let result = JsonDataFormat.marshal(body).unwrap();
144 match result {
145 Body::Text(s) => assert!(s.contains("\"key\"")),
146 _ => panic!("expected Body::Text"),
147 }
148 }
149
150 #[test]
151 fn test_marshal_text_noop() {
152 let body = Body::Text("already text".to_string());
153 let result = JsonDataFormat.marshal(body).unwrap();
154 assert_eq!(result, Body::Text("already text".to_string()));
155 }
156
157 #[test]
158 fn test_marshal_unsupported_variant() {
159 let body = Body::Xml("<root/>".to_string());
160 let result = JsonDataFormat.marshal(body);
161 assert!(matches!(result, Err(CamelError::TypeConversionFailed(_))));
162 }
163
164 #[test]
165 fn test_marshal_bytes_to_text() {
166 let body = Body::Bytes(Bytes::from_static(b"{\"key\":\"val\"}"));
167 let result = JsonDataFormat.marshal(body).unwrap();
168 match result {
169 Body::Text(s) => assert!(s.contains("\"key\"")),
170 _ => panic!("expected Body::Text"),
171 }
172 }
173
174 #[test]
175 fn test_marshal_invalid_bytes_returns_error() {
176 let body = Body::Bytes(Bytes::from_static(b"not json"));
177 let result = JsonDataFormat.marshal(body);
178 assert!(matches!(result, Err(CamelError::TypeConversionFailed(_))));
179 }
180}