Skip to main content

request_shadow/
backend.rs

1//! The async backend abstraction.
2
3use std::collections::BTreeMap;
4
5use async_trait::async_trait;
6use bytes::Bytes;
7
8use crate::error::ShadowError;
9
10/// What both legs of a shadow call return.
11#[derive(Clone, Debug, PartialEq, Eq)]
12pub struct ResponseRecord {
13    /// Whether the call completed normally. Backends that handle their own
14    /// errors should leave this `true` and put any error payload in `body`.
15    pub ok: bool,
16    /// HTTP-ish status code (or 0 for non-HTTP calls). Diffed unless the
17    /// caller adds it to [`crate::config::IgnoreField::Status`].
18    pub status: u16,
19    /// Sorted-by-key headers map. Diffed unless [`crate::config::IgnoreField::Headers`].
20    pub headers: BTreeMap<String, String>,
21    /// Response body, opaque.
22    pub body: Bytes,
23}
24
25impl ResponseRecord {
26    /// Construct a success record from a body — handy in tests.
27    pub fn ok(body: Vec<u8>) -> Self {
28        Self {
29            ok: true,
30            status: 200,
31            headers: BTreeMap::new(),
32            body: Bytes::from(body),
33        }
34    }
35
36    /// Construct a failure record.
37    pub fn err(status: u16, body: Vec<u8>) -> Self {
38        Self {
39            ok: false,
40            status,
41            headers: BTreeMap::new(),
42            body: Bytes::from(body),
43        }
44    }
45
46    /// Convenience: set a header. Returns `self` for chaining.
47    #[must_use]
48    pub fn with_header(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
49        self.headers.insert(key.into(), value.into());
50        self
51    }
52}
53
54/// The async surface the shadower drives. Implement once per transport.
55#[async_trait]
56pub trait Backend: Send + Sync {
57    /// Issue a call. The input is opaque so this trait works for HTTP bodies,
58    /// gRPC bytes, raw JSON, MessagePack — anything that fits in a `&[u8]`.
59    async fn call(&self, input: &[u8]) -> Result<ResponseRecord, ShadowError>;
60}