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}