camel_processor/
json_schema_validate.rs1use std::future::Future;
2use std::pin::Pin;
3use std::task::{Context, Poll};
4
5use tower::Service;
6
7use camel_api::body::Body;
8use camel_api::{CamelError, Exchange};
9
10pub struct JsonSchemaValidateService<P> {
19 inner: P,
20 validator: jsonschema::Validator,
21}
22
23impl<P> std::fmt::Debug for JsonSchemaValidateService<P> {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 f.debug_struct("JsonSchemaValidateService")
26 .finish_non_exhaustive()
27 }
28}
29
30impl<P> Clone for JsonSchemaValidateService<P>
31where
32 P: Clone,
33{
34 fn clone(&self) -> Self {
35 Self {
36 inner: self.inner.clone(),
37 validator: self.validator.clone(),
38 }
39 }
40}
41
42impl<P> JsonSchemaValidateService<P> {
43 pub fn new(inner: P, schema: &serde_json::Value) -> Result<Self, CamelError> {
46 let validator = jsonschema::validator_for(schema)
47 .map_err(|e| CamelError::RouteError(format!("invalid JSON schema: {e}")))?;
48 Ok(Self { inner, validator })
49 }
50}
51
52impl<P> Service<Exchange> for JsonSchemaValidateService<P>
53where
54 P: Service<Exchange, Response = Exchange, Error = CamelError> + Clone + Send + 'static,
55 P::Future: Send,
56{
57 type Response = Exchange;
58 type Error = CamelError;
59 type Future = Pin<Box<dyn Future<Output = Result<Exchange, CamelError>> + Send>>;
60
61 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
62 self.inner.poll_ready(cx)
63 }
64
65 fn call(&mut self, exchange: Exchange) -> Self::Future {
66 let result = match &exchange.input.body {
68 Body::Json(v) => {
69 let errors: Vec<String> = self
70 .validator
71 .iter_errors(v)
72 .map(|e| format!("{e} at {}", e.instance_path()))
73 .collect();
74 if errors.is_empty() {
75 Ok(())
76 } else {
77 Err(errors.join("; "))
78 }
79 }
80 _ => Ok(()),
81 };
82 match result {
83 Ok(()) => {
84 let fut = self.inner.call(exchange);
85 Box::pin(fut)
86 }
87 Err(msg) => Box::pin(async move {
88 Err(CamelError::ValidationError(format!(
89 "JSON schema validation failed: {msg}"
90 )))
91 }),
92 }
93 }
94}