1use std::fmt::Display;
8
9use reqwest::{ClientBuilder, RequestBuilder};
10
11use crate::error::Error;
12use crate::pagination::ListResponse;
13
14pub mod error;
15pub mod pagination;
16pub mod v2;
17
18const BASE_URL: &str = "https://services.nvd.nist.gov/rest/json/";
19
20#[derive(Debug, Clone)]
21pub struct NVDApi {
22 base_path: String,
23 version: String,
24 client: reqwest::Client,
25}
26
27pub enum ApiVersion {
28 V2_0,
29}
30
31impl Default for ApiVersion {
32 fn default() -> Self {
33 Self::V2_0
34 }
35}
36
37impl Display for ApiVersion {
38 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39 write!(
40 f,
41 "{}",
42 match self {
43 ApiVersion::V2_0 => String::from("2.0"),
44 }
45 )
46 }
47}
48
49impl NVDApi {
50 pub fn new(api_token: Option<String>, version: ApiVersion) -> Result<Self, Error> {
51 let mut headers = reqwest::header::HeaderMap::new();
52 if let Some(api_token) = api_token {
53 let mut auth_value = reqwest::header::HeaderValue::from_str(&format!("Bearer {api_token}"))
54 .map_err(|source| Error::InvalidApiToken { source })?;
55 auth_value.set_sensitive(true);
56 headers.insert(reqwest::header::AUTHORIZATION, auth_value);
57 }
58 let api_client = ClientBuilder::new()
59 .default_headers(headers)
60 .build()
61 .map_err(|source| Error::BuildingClient { source })?;
62 Ok(NVDApi {
63 base_path: BASE_URL.to_owned(),
64 version: version.to_string(),
65 client: api_client,
66 })
67 }
68}
69
70impl NVDApi {
71 pub async fn request(&self, request: RequestBuilder) -> Result<ListResponse, Error> {
72 let request = request.build()?;
73 let json = self
74 .client
75 .execute(request)
76 .await
77 .map_err(|source| Error::RequestFailed { source })?
78 .text()
79 .await
80 .map_err(|source| Error::ResponseIo { source })?;
81 let result = serde_json::from_str(&json).map_err(|source| Error::JsonParse { source })?;
82 Ok(result)
83 }
84}