1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
//! Module for fetching documents via HTTP

use std::fmt::{Display, Formatter};

use anyhow::anyhow;
use reqwest::blocking::Client;
use reqwest::Error;
use serde_json::Value;

/// Type of authentication to use
#[derive(Debug, Clone)]
pub enum HttpAuth {
  /// Username and Password
  User(String, Option<String>),
  /// Bearer token
  Token(String)
}

/// Fetches the JSON from a URL
pub fn fetch_json_from_url(url: &String, auth: &Option<HttpAuth>) -> anyhow::Result<(String, Value)> {
  let client = Client::new();
  let request = match auth {
    &Some(ref auth) => {
      match auth {
        &HttpAuth::User(ref username, ref password) => client.get(url).basic_auth(username.clone(), password.clone()),
        &HttpAuth::Token(ref token) => client.get(url).bearer_auth(token.clone())
      }
    },
    &None => client.get(url)
  };

  match request.send() {
    Ok(res) => if res.status().is_success() {
      let pact_json: Result<Value, Error> = res.json();
      match pact_json {
        Ok(ref json) => Ok((url.clone(), json.clone())),
        Err(err) => Err(anyhow!("Failed to parse JSON - {}", err))
      }
    } else {
      Err(anyhow!("Request failed with status - {}", res.status()))
    },
    Err(err) => Err(anyhow!("Request failed - {}", err))
  }
}

impl Display for HttpAuth {
  fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
    match *self {
      HttpAuth::Token(ref t) =>
        write!(f, "Token({:*<width$})", t.get(0..4).unwrap_or(""), width = t.len()),
      HttpAuth::User(ref u, ref p) => {
        if let Some(pass) = p {
          write!(f, "User({}, {:*<width$})", u, pass.get(0..4).unwrap_or(""), width = pass.len())
        } else {
          write!(f, "User({}, [no password])", u)
        }
      }
    }
  }
}