verity_client/
request.rs

1use std::convert::TryFrom;
2
3use http::{HeaderName, HeaderValue};
4use reqwest::{header::HeaderMap, Body, Request};
5use serde::Serialize;
6
7use crate::client::{VerityClient, VerityResponse};
8
9/// A builder to construct the properties of a `Request`.
10///
11/// To construct a `RequestBuilder`, refer to the `Client` documentation.
12#[must_use = "RequestBuilder does nothing until you 'send' it"]
13pub struct RequestBuilder {
14    pub(crate) client: VerityClient,
15    pub(crate) inner: reqwest::RequestBuilder,
16}
17
18impl RequestBuilder {
19    /// Add a `Header` to this Request.
20    ///
21    /// This method allows you to add a single header to the request.
22    pub fn header<K, V>(self, key: K, value: V) -> Self
23    where
24        HeaderName: TryFrom<K>,
25        <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
26        HeaderValue: TryFrom<V>,
27        <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
28    {
29        RequestBuilder {
30            inner: self.inner.header(key, value),
31            ..self
32        }
33    }
34
35    /// Add a set of Headers to the existing ones on this Request.
36    ///
37    /// This method merges the provided headers with any already set on the request.
38    pub fn headers(self, headers: HeaderMap) -> Self {
39        RequestBuilder {
40            inner: self.inner.headers(headers),
41            ..self
42        }
43    }
44
45    /// Set the request body.
46    ///
47    /// This method sets the body of the request to the provided value.
48    pub fn body<T: Into<Body>>(self, body: T) -> Self {
49        RequestBuilder {
50            inner: self.inner.body(body),
51            ..self
52        }
53    }
54
55    /// Send a JSON body.
56    ///
57    /// This method serializes the provided data structure as JSON and sets it as the request body.
58    ///
59    /// # Errors
60    ///
61    /// Serialization can fail if `T`'s implementation of `Serialize` decides to
62    /// fail, or if `T` contains a map with non-string keys.
63    pub fn json<T: Serialize + ?Sized>(self, json: &T) -> Self {
64        RequestBuilder {
65            inner: self.inner.json(json),
66            ..self
67        }
68    }
69
70    /// Add an instruction to prove failed request.
71    ///
72    /// This method adds a header to instruct Verity Prover to prove the response,
73    /// even if its status code is not success.
74    pub fn prove_failed_request(self) -> Self {
75        RequestBuilder {
76            inner: self.inner.header("T-PROVE-FAILED-REQ", "true"),
77            ..self
78        }
79    }
80
81    /// Add a Redact instruction.
82    ///
83    /// This method adds a header to instruct Verity Prover on how to hide sensitive data.
84    pub fn redact(self, redact: String) -> Self {
85        RequestBuilder {
86            inner: self
87                .inner
88                .header("T-REDACTED", HeaderValue::from_str(&redact).unwrap()),
89            ..self
90        }
91    }
92
93    /// Build a `Request`.
94    ///
95    /// This method constructs the request, which can then be
96    /// inspected, modified and executed with `VerityClient::execute()`.
97    pub fn build(self) -> reqwest::Result<Request> {
98        self.inner.build()
99    }
100
101    /// Build a `Request`, which can be inspected, modified and executed with
102    /// `VerityClient::execute()`.
103    ///
104    /// This is similar to [`RequestBuilder::build()`], but also returns the
105    /// embedded `VerityClient`.
106    pub fn build_split(self) -> (VerityClient, reqwest::Result<Request>) {
107        let Self { inner, client, .. } = self;
108        let (_, req) = inner.build_split();
109
110        (client, req)
111    }
112
113    /// Constructs the Request and sends it to the target URL, returning a
114    /// future Response.
115    ///
116    /// # Errors
117    ///
118    /// This method fails if there was an error while sending request,
119    /// redirect loop was detected or redirect limit was exhausted.
120    ///
121    /// # Example
122    ///
123    /// ```no_run
124    /// # use anyhow::Error;
125    /// # use verity_client::client::{VerityClient, VerityClientConfig};
126    /// # async fn run() -> Result<(), Error> {
127    ///
128    ///
129    /// let config = VerityClientConfig {
130    ///     prover_url: String::from("http://127.0.0.1:8080"),
131    /// };
132    ///
133    /// let response = VerityClient::new(config)
134    ///     .get("https://hyper.rs")
135    ///     .send()
136    ///     .await?;
137    /// # Ok(())
138    /// # }
139    /// ```
140    pub async fn send(self) -> anyhow::Result<VerityResponse> {
141        let (mut client, req) = self.build_split();
142        client.execute_request(req?).await
143    }
144}