Skip to main content

kintone/
middleware.rs

1//! # Middleware System for Kintone Client
2//!
3//! This module provides a middleware system for the Kintone client that allows
4//! for intercepting and modifying requests and responses. Middleware can handle cross-cutting
5//! concerns such as retries, logging, authentication, and custom request/response processing.
6//!
7//! ## Core Concepts
8//!
9//! The middleware system is built around two fundamental concepts:
10//!
11//! ### Handler: Request → Response Function
12//! A [`Handler`] is essentially a function that transforms an HTTP request into an HTTP response.
13//! This is the core abstraction that represents any piece of logic that can process requests.
14//!
15//! ### Layer: Handler Stacking Mechanism  
16//! A [`Layer`] is a mechanism for "stacking" multiple Handlers to create a single, more powerful Handler.
17//! Layers allow you to compose functionality by wrapping one Handler with another, creating
18//! a chain where each layer can add behavior before and after the inner handler processes the request.
19//!
20//! ## How Stacking Works
21//!
22//! When you stack layers like this:
23//! ```ignore
24//! client_builder
25//!     .layer(RetryLayer::new().with_max_attempts(5)) // Layer A
26//!     .layer(LoggingLayer::new())                    // Layer B
27//!     .build()
28//! ```
29//!
30//! You get a handler stack that looks like:
31//! ```ignore
32//! RetryLayer(LoggingLayer(BaseHandler))
33//! ```
34//!
35//! Requests flow through: RetryLayer → LoggingLayer → BaseHandler  
36//! Responses flow back: BaseHandler → LoggingLayer → RetryLayer
37//!
38//! ## Built-in Middleware
39//!
40//! - [`RetryLayer`] - Automatically retries failed requests with exponential backoff
41//! - [`LoggingLayer`] - Logs request and response information for debugging
42//! - [`BasicAuthLayer`] - Adds HTTP Basic authentication headers to requests
43
44use std::{
45    borrow::Borrow,
46    io::{Cursor, Read},
47    sync::Arc,
48};
49
50use base64::Engine;
51use base64::engine::general_purpose::STANDARD as BASE64;
52use http::Request;
53use log::info;
54use serde::de::DeserializeOwned;
55
56use crate::error::ApiError;
57
58/// Represents the body of an HTTP request in the middleware system.
59///
60/// This abstraction allows for different types of request bodies while maintaining
61/// the ability to clone and reuse them for retry operations. The body can be:
62/// - Empty (void)
63/// - Bytes in memory (cloneable for retries)
64/// - A streaming reader (non-cloneable)
65///
66/// # Examples
67///
68/// ```ignore
69/// use std::fs::File;
70/// use std::io::BufReader;
71///
72/// // Empty body
73/// let body = RequestBody::void();
74///
75/// // JSON body from bytes
76/// let json_bytes = serde_json::to_vec(&data)?;
77/// let body = RequestBody::from_bytes(json_bytes);
78///
79/// // Streaming body from file
80/// let file = File::open("large_file.txt")?;
81/// let body = RequestBody::from_reader(BufReader::new(file));
82/// ```
83pub struct RequestBody(RequestBodyInner);
84
85impl RequestBody {
86    pub fn void() -> Self {
87        RequestBody(RequestBodyInner::Void)
88    }
89
90    pub fn from_bytes(bytes: Vec<u8>) -> Self {
91        RequestBody(RequestBodyInner::Bytes(Arc::from(bytes.into_boxed_slice())))
92    }
93
94    pub fn from_reader(reader: impl Read + Sync + Send + 'static) -> Self {
95        RequestBody(RequestBodyInner::Reader(Box::new(reader)))
96    }
97
98    pub fn try_clone(&self) -> Option<Self> {
99        match &self.0 {
100            RequestBodyInner::Void => Some(RequestBody(RequestBodyInner::Void)),
101            RequestBodyInner::Bytes(p) => Some(RequestBody(RequestBodyInner::Bytes(Arc::clone(p)))),
102            RequestBodyInner::Reader(_) => None, // Reader cannot be cloned
103        }
104    }
105
106    pub fn into_reader(self) -> impl Read {
107        self.into_ureq_body().into_reader()
108    }
109
110    pub(crate) fn into_ureq_body(self) -> ureq::SendBody<'static> {
111        match self.0 {
112            RequestBodyInner::Void => ureq::SendBody::none(),
113            RequestBodyInner::Bytes(b) => ureq::SendBody::from_owned_reader(Cursor::new(b)),
114            RequestBodyInner::Reader(reader) => ureq::SendBody::from_owned_reader(reader),
115        }
116    }
117}
118
119enum RequestBodyInner {
120    Void,
121    Bytes(Arc<[u8]>),
122    Reader(Box<dyn Read + Sync + Send + 'static>),
123}
124
125/// Represents the body of an HTTP response in the middleware system.
126///
127/// This wrapper around the raw response body provides methods for reading
128/// the response content, including JSON deserialization and streaming access.
129/// The body can only be consumed once due to its streaming nature.
130///
131/// # Examples
132///
133/// ```ignore
134/// // Read as JSON
135/// let data: MyStruct = response_body.read_json()?;
136///
137/// // Read as raw stream
138/// let reader = response_body.into_reader();
139/// std::io::copy(&mut reader, &mut output_file)?;
140/// ```
141pub struct ResponseBody(ureq::Body);
142
143impl ResponseBody {
144    const MAX_JSON_SIZE: u64 = 10 * 1024 * 1024;
145
146    pub(crate) fn from_ureq_body(body: ureq::Body) -> Self {
147        ResponseBody(body)
148    }
149
150    pub fn into_reader(self) -> impl Read + 'static {
151        self.0.into_reader()
152    }
153
154    pub fn read_json<D: DeserializeOwned>(&mut self) -> Result<D, ApiError> {
155        let body = self.0.with_config().limit(Self::MAX_JSON_SIZE).read_to_vec()?;
156        serde_json::from_slice(&body).map_err(|e| e.into())
157    }
158}
159
160//-----------------------------------------------------------------------------
161
162/// Core trait for handling HTTP requests in the middleware system.
163///
164/// **At its essence, a Handler is a function that transforms an HTTP request into an HTTP response.**
165/// This is the fundamental building block of the middleware system. Every Handler takes a request
166/// and produces either a successful response or an error.
167///
168/// Handlers form the foundation of the middleware system, where each middleware layer
169/// wraps a handler to add additional functionality while maintaining this core contract
170/// of `Request -> Response`.
171///
172/// # The Function-like Nature
173///
174/// You can think of a Handler as:
175/// ```ignore
176/// fn handle(request: Request) -> Result<Response, Error>
177/// ```
178///
179/// This simple concept allows for powerful composition through the middleware system.
180pub trait Handler: Send + Sync + 'static {
181    fn handle(
182        &self,
183        req: http::Request<RequestBody>,
184    ) -> Result<http::Response<ResponseBody>, ApiError>;
185}
186
187/// Trait for middleware layers that can wrap handlers to add functionality.
188///
189/// **A Layer is a mechanism for "stacking" multiple Handlers to create a single, more powerful Handler.**
190/// Think of it as a way to compose functionality by wrapping one Handler with another.
191///
192/// Each Layer takes an inner Handler and produces a new Handler that adds some behavior
193/// around the inner one. This creates a "Russian doll" effect where requests flow through
194/// each layer in order, and responses flow back through them in reverse order.
195///
196/// # The Stacking Concept
197///
198/// When you have multiple layers, they stack like this:
199/// ```ignore
200/// Layer3(Layer2(Layer1(BaseHandler)))
201/// ```
202///
203/// The request flows: Layer3 -> Layer2 -> Layer1 -> BaseHandler
204/// The response flows: BaseHandler -> Layer1 -> Layer2 -> Layer3
205///
206/// This allows each layer to:
207/// - Modify the request before passing it down
208/// - Modify the response after receiving it back
209/// - Add cross-cutting concerns (logging, retries, authentication, etc.)
210/// - Short-circuit the chain (e.g., return cached responses)
211///
212/// # Type Parameters
213///
214/// * `Inner` - The type of handler that this layer wraps
215///
216/// # Associated Types
217///
218/// * `Outer` - The type of handler returned after wrapping the inner handler
219///
220/// # Examples
221///
222/// ```ignore
223/// impl<Inner: Handler> Layer<Inner> for MyMiddleware {
224///     type Outer = MyHandler<Inner>;
225///
226///     fn layer(self, inner: Inner) -> Self::Outer {
227///         // Return a new handler that wraps the inner one
228///         MyHandler { inner, config: self }
229///     }
230/// }
231/// ```
232pub trait Layer<Inner: Handler>: Send + Sync + 'static {
233    type Outer: Handler;
234    fn layer(self, inner: Inner) -> Self::Outer;
235}
236
237//-----------------------------------------------------------------------------
238
239/// Type alias for a function that determines whether a request should be retried.
240///
241/// This function receives the original request (without body) and the response (or `ApiError`),
242/// and returns `true` if the request should be retried. The request body is
243/// removed to avoid ownership issues and because retry decisions are typically
244/// based on response status rather than request content.
245///
246/// # Examples
247///
248/// ```no_run
249/// use kintone::middleware::ShouldRetryFn;
250/// let should_retry: Box<ShouldRetryFn> = Box::new(|req, resp_or_err| {
251///     let Ok(resp) = resp_or_err else {
252///         return false;  // Never retry on API errors.
253///     };
254///     // Retry on server errors (5xx) or specific client errors
255///     resp.status().is_server_error() || resp.status() == 429
256/// });
257/// ```
258pub type ShouldRetryFn = dyn Fn(&http::Request<()>, Result<&http::Response<ResponseBody>, &ApiError>) -> bool
259    + Send
260    + Sync
261    + 'static;
262
263/// Middleware layer that automatically retries failed requests with exponential backoff.
264///
265/// This layer is particularly useful for handling transient errors like database locks
266/// (GAIA_DA02 in Kintone) or network timeouts. It implements exponential backoff to
267/// avoid overwhelming the server with rapid retry attempts.
268///
269/// # Retry Logic
270///
271/// - Requests are retried up to `max_attempts` times
272/// - Delay between retries starts at `initial_delay` and doubles after each attempt
273/// - Delay is capped at `max_delay` to prevent excessively long waits
274/// - Only requests with cloneable bodies can be retried (streaming requests are not retried)
275///
276/// # Examples
277///
278/// ```rust
279/// use std::time::Duration;
280/// use kintone::middleware::RetryLayer;
281///
282/// // Retry up to 5 times with exponential backoff
283/// let retry_layer = RetryLayer::new()
284///     .with_max_attempts(5)
285///     .with_initial_delay(Duration::from_millis(500))
286///     .with_max_delay(Duration::from_secs(30));
287/// ```
288/// RetryLayer controls automatic retry logic for failed requests.
289///
290/// Use builder-style methods to configure retry policy.
291pub struct RetryLayer {
292    max_attempts: usize,
293    initial_delay: std::time::Duration,
294    max_delay: std::time::Duration,
295    should_retry: Box<ShouldRetryFn>,
296}
297
298impl RetryLayer {
299    const NONRETRYABLE_CODES: &[&str] = &[
300        "CB_IL02", // "不正なリクエストです。"
301    ];
302
303    pub const DEFAULT_MAX_ATTEMPTS: usize = 5;
304    pub const DEFAULT_INITIAL_DELAY: std::time::Duration = std::time::Duration::from_secs(1);
305    pub const DEFAULT_MAX_DELAY: std::time::Duration = std::time::Duration::from_secs(8);
306    pub const DEFAULT_SHOULD_RETRY_FN: &ShouldRetryFn = &|_, resp_or_err| match resp_or_err {
307        Ok(resp) => !resp.status().is_success(),
308        Err(err) => {
309            if let ApiError::Kintone(kintone_err) = err {
310                !Self::NONRETRYABLE_CODES.contains(&kintone_err.code.borrow())
311            } else {
312                true
313            }
314        }
315    };
316
317    /// Creates a new RetryLayer with default settings.
318    pub fn new() -> Self {
319        RetryLayer {
320            max_attempts: Self::DEFAULT_MAX_ATTEMPTS,
321            initial_delay: Self::DEFAULT_INITIAL_DELAY,
322            max_delay: Self::DEFAULT_MAX_DELAY,
323            should_retry: Box::new(Self::DEFAULT_SHOULD_RETRY_FN),
324        }
325    }
326
327    /// Sets the maximum number of retry attempts.
328    /// `max_attempts` must be ≧ 1.
329    /// If `max_attempts` is 1, retries are disabled.
330    pub fn with_max_attempts(mut self, max_attempts: usize) -> Self {
331        if max_attempts == 0 {
332            panic!("max_attempts must be >= 1");
333        }
334        self.max_attempts = max_attempts;
335        self
336    }
337
338    /// Sets the initial delay before the first retry.
339    pub fn with_initial_delay(mut self, initial_delay: std::time::Duration) -> Self {
340        self.initial_delay = initial_delay;
341        self
342    }
343
344    /// Sets the maximum delay between retries.
345    pub fn with_max_delay(mut self, max_delay: std::time::Duration) -> Self {
346        self.max_delay = max_delay;
347        self
348    }
349
350    /// Sets the retry decision function.
351    pub fn with_should_retry(mut self, should_retry: Box<ShouldRetryFn>) -> Self {
352        self.should_retry = should_retry;
353        self
354    }
355}
356
357impl Default for RetryLayer {
358    fn default() -> Self {
359        Self::new()
360    }
361}
362
363impl<Inner: Handler> Layer<Inner> for RetryLayer {
364    type Outer = RetryHandler<Inner>;
365    fn layer(self, inner: Inner) -> Self::Outer {
366        RetryHandler { inner, layer: self }
367    }
368}
369
370/// Handler implementation that wraps another handler with retry logic.
371///
372/// This handler implements the actual retry behavior for the [`RetryLayer`].
373/// It attempts requests multiple times according to the configured retry policy,
374/// with exponential backoff between attempts.
375///
376/// This is an internal implementation detail and should not be used directly.
377pub struct RetryHandler<Inner> {
378    inner: Inner,
379    layer: RetryLayer,
380}
381
382impl<Inner: Handler> Handler for RetryHandler<Inner> {
383    fn handle(
384        &self,
385        req: http::Request<RequestBody>,
386    ) -> Result<http::Response<ResponseBody>, ApiError> {
387        if self.layer.max_attempts == 1 {
388            return self.inner.handle(req);
389        }
390
391        let (parts, body) = req.into_parts();
392
393        let mut attempts = 1;
394        let mut delay = self.layer.initial_delay;
395
396        loop {
397            let Some(body_cloned) = body.try_clone() else {
398                // Body cannot be cloned. We cannot retry this request.
399                let req = Request::from_parts(parts, body);
400                return self.inner.handle(req);
401            };
402            let req_cloned = http::Request::from_parts(parts.clone(), body_cloned);
403            let result = self.inner.handle(req_cloned);
404
405            match result {
406                Ok(resp) => {
407                    if attempts >= self.layer.max_attempts {
408                        return Ok(resp);
409                    }
410                    let req_nobody = http::Request::from_parts(parts.clone(), ());
411                    let retry_ok = (self.layer.should_retry)(&req_nobody, Ok(&resp));
412                    if !retry_ok {
413                        return Ok(resp);
414                    }
415                    // do retry
416                }
417                Err(e) => {
418                    if attempts >= self.layer.max_attempts {
419                        return Err(e);
420                    }
421                    let req_nobody = http::Request::from_parts(parts.clone(), ());
422                    let retry_ok = (self.layer.should_retry)(&req_nobody, Err(&e));
423                    if !retry_ok {
424                        return Err(e);
425                    }
426                    // do retry
427                }
428            }
429
430            std::thread::sleep(delay);
431            delay = std::cmp::min(delay * 2, self.layer.max_delay);
432            attempts += 1;
433        }
434    }
435}
436
437//-----------------------------------------------------------------------------
438
439/// Middleware layer that logs HTTP request and response information.
440///
441/// This layer provides debugging capabilities by logging details about each
442/// HTTP request and response.
443///
444/// - Uses the [`log`](https://docs.rs/log/latest/log/) crate for logging output.
445/// - All logs are emitted at the `info` level.
446/// - You can use any logger compatible with the `log` crate (e.g., `env_logger`, `tracing`, etc.).
447///
448/// # Logged Information
449///
450/// - Request: HTTP method and URL
451/// - Request body (if available)
452/// - Response: HTTP status code or error details
453///
454/// # Examples
455///
456/// ```rust
457/// use kintone::middleware::LoggingLayer;
458///
459/// env_logger::init();
460/// let logging_layer = LoggingLayer::new();
461/// ```
462pub struct LoggingLayer {
463    log_target: String,
464    enabled: bool,
465}
466
467impl LoggingLayer {
468    const DEFAULT_LOG_TARGET: &str = "kintone";
469
470    /// Creates a new LoggingLayer with logging enabled by default.
471    pub fn new() -> Self {
472        LoggingLayer {
473            log_target: Self::DEFAULT_LOG_TARGET.to_owned(),
474            enabled: true,
475        }
476    }
477
478    /// Enables or disables logging for this layer. (builder style)
479    ///
480    /// # Examples
481    ///
482    /// ```rust
483    /// use kintone::middleware::LoggingLayer;
484    /// let logging_layer = LoggingLayer::new().with_enabled(false);
485    /// ```
486    pub fn with_enabled(mut self, enabled: bool) -> Self {
487        self.enabled = enabled;
488        self
489    }
490
491    /// Sets the log target for this layer. (builder style)
492    ///
493    /// See the document of [log][log] crate for log targets.
494    ///
495    /// [log]: https://docs.rs/log/latest/log/
496    ///
497    /// # Examples
498    ///
499    /// ```rust
500    /// use kintone::middleware::LoggingLayer;
501    /// let logging_layer = LoggingLayer::new().with_log_target("kintone::access_log");
502    /// ```
503    pub fn with_log_target(mut self, target: impl Into<String>) -> Self {
504        self.log_target = target.into();
505        self
506    }
507}
508
509impl Default for LoggingLayer {
510    fn default() -> Self {
511        LoggingLayer::new()
512    }
513}
514
515impl<Inner: Handler> Layer<Inner> for LoggingLayer {
516    type Outer = LoggingHandler<Inner>;
517    fn layer(self, inner: Inner) -> Self::Outer {
518        LoggingHandler {
519            inner,
520            log_target: self.log_target,
521            enabled: self.enabled,
522        }
523    }
524}
525
526/// Handler implementation that wraps another handler with logging functionality.
527///
528/// This handler implements the actual logging behavior for the [`LoggingLayer`].
529/// It logs request details before calling the inner handler and logs response
530/// details after receiving the response.
531///
532/// This is an internal implementation detail and should not be used directly.
533pub struct LoggingHandler<Inner> {
534    inner: Inner,
535    log_target: String,
536    enabled: bool,
537}
538
539impl<Inner: Handler> Handler for LoggingHandler<Inner> {
540    fn handle(
541        &self,
542        req: http::Request<RequestBody>,
543    ) -> Result<http::Response<ResponseBody>, ApiError> {
544        if !self.enabled {
545            return self.inner.handle(req);
546        }
547
548        info!(target: &self.log_target, "Request: method={}, url={:?}", req.method(), req.uri());
549        if let Some(body) = req.body().try_clone() {
550            let mut buf = String::new();
551            if body.into_reader().read_to_string(&mut buf).is_ok() {
552                info!(target: &self.log_target, "Request body:\n{buf}");
553            }
554        }
555        let result = self.inner.handle(req);
556        match &result {
557            Ok(resp) => {
558                info!(target: &self.log_target, "Response: status={}", resp.status().as_u16());
559            }
560            Err(e) => info!(target: &self.log_target, "Response: error={e}"),
561        }
562        result
563    }
564}
565
566//-----------------------------------------------------------------------------
567
568/// Middleware layer that adds HTTP Basic authentication headers to requests.
569///
570/// This layer automatically adds the `Authorization` header with Basic authentication
571/// credentials to all outgoing requests.
572///
573/// # Examples
574///
575/// ```rust
576/// use kintone::middleware::BasicAuthLayer;
577///
578/// // Enable Basic authentication
579/// let basic_auth = BasicAuthLayer::new(Some(("username".to_string(), "password".to_string())));
580///
581/// // Disable Basic authentication
582/// let no_auth = BasicAuthLayer::new(None);
583/// ```
584///
585/// Combined with other middleware:
586/// ```rust
587/// use std::time::Duration;
588/// use kintone::client::{Auth, KintoneClientBuilder};
589/// use kintone::middleware;
590///
591/// let client = KintoneClientBuilder::new(
592///         "https://your-domain.cybozu.com",
593///         Auth::api_token("your-api-token".to_owned())
594///     )
595///     .layer(middleware::BasicAuthLayer::new(Some(("basicauth_user".to_string(), "basicauth_password".to_string()))))
596///     .layer(middleware::RetryLayer::new()
597///         .with_max_attempts(5)
598///         .with_initial_delay(Duration::from_secs(1))
599///         .with_max_delay(Duration::from_secs(8))
600///     )
601///     .layer(middleware::LoggingLayer::new())
602///     .build();
603/// ```
604pub struct BasicAuthLayer {
605    credentials: Option<(String, String)>,
606}
607
608impl BasicAuthLayer {
609    /// Creates a new Basic authentication layer with optional credentials.
610    ///
611    /// # Arguments
612    ///
613    /// * `credentials` - Optional tuple of (username, password) for Basic authentication.
614    ///   Pass `None` to disable Basic authentication, or `Some((username, password))` to enable it.
615    ///
616    /// # Examples
617    ///
618    /// ```rust
619    /// use kintone::middleware::BasicAuthLayer;
620    ///
621    /// // Enable Basic authentication
622    /// let basic_auth = BasicAuthLayer::new(Some(("myuser".to_string(), "mypassword".to_string())));
623    ///
624    /// // Disable Basic authentication
625    /// let no_auth = BasicAuthLayer::new(None);
626    /// ```
627    pub fn new(credentials: Option<(String, String)>) -> Self {
628        BasicAuthLayer { credentials }
629    }
630
631    /// Creates a new Basic authentication layer with the provided credentials.
632    ///
633    /// This is a convenience method that automatically wraps the credentials in `Some()`.
634    ///
635    /// # Arguments
636    ///
637    /// * `username` - The username for Basic authentication
638    /// * `password` - The password for Basic authentication
639    ///
640    /// # Examples
641    ///
642    /// ```rust
643    /// use kintone::middleware::BasicAuthLayer;
644    ///
645    /// let basic_auth = BasicAuthLayer::enabled("myuser", "mypassword");
646    /// ```
647    pub fn enabled(username: impl Into<String>, password: impl Into<String>) -> Self {
648        BasicAuthLayer {
649            credentials: Some((username.into(), password.into())),
650        }
651    }
652
653    /// Creates a new Basic authentication layer with authentication disabled.
654    ///
655    /// This is a convenience method that creates a layer that won't add any
656    /// authentication headers to requests.
657    ///
658    /// # Examples
659    ///
660    /// ```rust
661    /// use kintone::middleware::BasicAuthLayer;
662    ///
663    /// let no_auth = BasicAuthLayer::disabled();
664    /// ```
665    pub fn disabled() -> Self {
666        BasicAuthLayer { credentials: None }
667    }
668
669    fn encode_credentials(&self) -> Option<String> {
670        self.credentials.as_ref().map(|(username, password)| {
671            let credentials = format!("{username}:{password}");
672            let encoded = BASE64.encode(credentials.as_bytes());
673            format!("Basic {encoded}")
674        })
675    }
676}
677
678impl<Inner: Handler> Layer<Inner> for BasicAuthLayer {
679    type Outer = BasicAuthHandler<Inner>;
680    fn layer(self, inner: Inner) -> Self::Outer {
681        BasicAuthHandler { inner, layer: self }
682    }
683}
684
685/// Handler implementation that wraps another handler with Basic authentication.
686///
687/// This handler implements the actual Basic auth behavior for the [`BasicAuthLayer`].
688/// It adds the Authorization header to requests before passing them to the inner handler.
689///
690/// This is an internal implementation detail and should not be used directly.
691pub struct BasicAuthHandler<Inner> {
692    inner: Inner,
693    layer: BasicAuthLayer,
694}
695
696impl<Inner: Handler> Handler for BasicAuthHandler<Inner> {
697    fn handle(
698        &self,
699        mut req: http::Request<RequestBody>,
700    ) -> Result<http::Response<ResponseBody>, ApiError> {
701        if let Some(auth_header_value) = self.layer.encode_credentials() {
702            req.headers_mut()
703                .insert(http::header::AUTHORIZATION, auth_header_value.parse().unwrap());
704        }
705        self.inner.handle(req)
706    }
707}
708
709//-----------------------------------------------------------------------------
710
711/// A no-op middleware layer that provides no additional functionality.
712///
713/// This layer is used as the base case in the middleware stack. When applied,
714/// it simply returns the inner handler unchanged. It's primarily used internally
715/// by the [`KintoneClientBuilder`] as the starting point for building middleware stacks.
716///
717/// [`KintoneClientBuilder`]: crate::client::KintoneClientBuilder
718pub struct NoLayer;
719
720impl<Inner: Handler> Layer<Inner> for NoLayer {
721    type Outer = Inner;
722    fn layer(self, inner: Inner) -> Self::Outer {
723        inner
724    }
725}
726
727/// A stack of two middleware layers that composes them into a single layer.
728///
729/// This type allows for building chains of middleware by combining pairs of layers.
730/// When applied, it first applies the `Tail` layer to the inner handler, then
731/// applies the `Head` layer to the result.
732///
733/// This is an internal implementation detail used by the middleware system to
734/// build complex middleware stacks from individual layers.
735///
736/// # Type Parameters
737///
738/// * `Head` - The outer layer (applied last)
739/// * `Tail` - The inner layer (applied first)
740///
741/// # Examples
742///
743/// ```ignore
744/// // This creates a stack: LoggingLayer -> RetryLayer -> Handler
745/// let stack = Stack::new(LoggingLayer::new(), RetryLayer::new(...));
746/// ```
747pub struct Stack<Head, Tail>(Head, Tail);
748
749impl<Head, Tail> Stack<Head, Tail> {
750    pub fn new(head: Head, tail: Tail) -> Self {
751        Stack(head, tail)
752    }
753}
754
755impl<Inner, Head, Tail> Layer<Inner> for Stack<Head, Tail>
756where
757    Inner: Handler,
758    Head: Layer<Tail::Outer>,
759    Tail: Layer<Inner>,
760{
761    type Outer = Head::Outer;
762    fn layer(self, inner: Inner) -> Self::Outer {
763        self.0.layer(self.1.layer(inner))
764    }
765}