Skip to main content

base_sensible_wrapper/
interface.rs

1use anyhow::{Context, Result};
2use reqwest::{
3    Body, Method, Request,
4    header::{HeaderName, HeaderValue},
5};
6use reqwest_middleware::{ClientWithMiddleware, RequestBuilder};
7use serde::Serialize;
8use std::collections::HashMap;
9use std::fmt::Display;
10
11/// The public interface used to access any api. Should be implemented to provide specific
12/// details about how to make a given api call.
13pub trait ApiInterface: Send + Sync {
14    /// Build a request based on the provided details. Provided, and should not be overridden
15    /// except in very specific cases.
16    fn build_request<
17        E: Display,
18        HK: Into<HeaderName>,
19        HV: Into<HeaderValue>,
20        P: Serialize,
21        B: Serialize,
22    >(
23        &self,
24        client: ClientWithMiddleware,
25        endpoint: E,
26        method: Method,
27        headers: HashMap<HK, HV>,
28        params: Option<P>,
29        body: Option<B>,
30    ) -> Result<Request> {
31        let url = format!("{}{endpoint}", self.get_base_url());
32        let request = Request::new(method, url.parse()?);
33
34        let mut builder = RequestBuilder::from_parts(client, request);
35        builder = builder.headers(
36            headers
37                .into_iter()
38                .map(|(k, v)| (k.into(), v.into()))
39                .collect(),
40        );
41        builder = self.get_auth_info(builder);
42
43        if let Some(params) = params {
44            builder = builder.query(&params);
45        }
46
47        if let Some(body) = body {
48            let body = serde_json::to_string(&body)?;
49            builder = builder.body(Body::from(body));
50        }
51
52        builder = self.additional_modifications(builder);
53
54        builder
55            .build()
56            .context("Cannot build request inside ApiInterface")
57    }
58
59    /// The base url to use
60    fn get_base_url(&self) -> String;
61    /// How the interface authenticates
62    fn get_auth_info(&self, request: RequestBuilder) -> RequestBuilder;
63    /// If any additional modifications need to be made to the request, this member can
64    /// be overridden by impls. Otherwise, it returns the request unmodified
65    fn additional_modifications(&self, request: RequestBuilder) -> RequestBuilder {
66        request
67    }
68}