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}