ring_api/
client.rs

1//! A RING HTTP API client.
2
3use serde::Serialize;
4use reqwest::{ Client as ReqwestClient, RequestBuilder };
5use crate::{
6    requests::{ Request, RequestBody },
7    error::Result,
8    multipart::to_form,
9};
10
11/// The base URL for the RING API.
12static BASE_URL: &str = "http://protein.bio.unipd.it/ringws";
13
14/// The main entry point to the RING webservice.
15#[derive(Debug, Clone)]
16pub struct Client {
17    /// The backing HTTP client.
18    client: ReqwestClient,
19}
20
21impl Client {
22    /// Creates a RING web client.
23    pub fn new() -> Self {
24        Client {
25            client: ReqwestClient::new()
26        }
27    }
28
29    /// Sending requests.
30    pub fn send<R: Request>(&self, request: R) -> Result<R::Response> {
31        let endpoint = request.endpoint();
32        let endpoint = endpoint.trim_matches('/');
33        let url = format!("{}/{}", BASE_URL, endpoint);
34
35        self.client
36            .request(R::METHOD, &url)
37            .headers(request.headers())
38            .ring_body(request.body())?
39            .send()
40            .and_then(|mut resp| resp.json())
41            .map_err(From::from)
42    }
43}
44
45impl Default for Client {
46    fn default() -> Self {
47        Self::new()
48    }
49}
50
51/// Private trait for extending the client builder so that it can send the body
52/// in different formats, decided dynamically.
53trait RequestBuilderExt: Sized {
54    /// Sends the body in the specified format, or does nothing if it is `None`.
55    fn ring_body<T: Serialize>(self, body: RequestBody<T>) -> Result<Self>;
56}
57
58impl RequestBuilderExt for RequestBuilder {
59    fn ring_body<T: Serialize>(self, body: RequestBody<T>) -> Result<Self> {
60        Ok(match body {
61            RequestBody::None => self,
62            RequestBody::Json(value) => self.json(&value),
63            RequestBody::Query(value) => self.query(&value),
64            RequestBody::Form(value) => self.form(&value),
65            RequestBody::Multipart(value) => self.multipart(to_form(&value)?),
66        })
67    }
68}