datadog_api_client/datadogV1/api/
api_authentication.rs

1// Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License.
2// This product includes software developed at Datadog (https://www.datadoghq.com/).
3// Copyright 2019-Present Datadog, Inc.
4use crate::datadog;
5use reqwest::header::{HeaderMap, HeaderValue};
6use serde::{Deserialize, Serialize};
7
8/// ValidateError is a struct for typed errors of method [`AuthenticationAPI::validate`]
9#[derive(Debug, Clone, Serialize, Deserialize)]
10#[serde(untagged)]
11pub enum ValidateError {
12    APIErrorResponse(crate::datadogV1::model::APIErrorResponse),
13    UnknownValue(serde_json::Value),
14}
15
16/// All requests to Datadog’s API must be authenticated.
17/// Requests that write data require reporting access and require an `API key`.
18/// Requests that read data require full access and also require an `application key`.
19///
20/// **Note:** All Datadog API clients are configured by default to consume Datadog US site APIs.
21/// If you are on the Datadog EU site, set the environment variable `DATADOG_HOST` to
22/// `<https://api.datadoghq.eu`> or override this value directly when creating your client.
23///
24/// [Manage your account’s API and application keys](<https://app.datadoghq.com/organization-settings/>) in Datadog, and see the [API and Application Keys page](<https://docs.datadoghq.com/account_management/api-app-keys/>) in the documentation.
25#[derive(Debug, Clone)]
26pub struct AuthenticationAPI {
27    config: datadog::Configuration,
28    client: reqwest_middleware::ClientWithMiddleware,
29}
30
31impl Default for AuthenticationAPI {
32    fn default() -> Self {
33        Self::with_config(datadog::Configuration::default())
34    }
35}
36
37impl AuthenticationAPI {
38    pub fn new() -> Self {
39        Self::default()
40    }
41    pub fn with_config(config: datadog::Configuration) -> Self {
42        let mut reqwest_client_builder = reqwest::Client::builder();
43
44        if let Some(proxy_url) = &config.proxy_url {
45            let proxy = reqwest::Proxy::all(proxy_url).expect("Failed to parse proxy URL");
46            reqwest_client_builder = reqwest_client_builder.proxy(proxy);
47        }
48
49        let mut middleware_client_builder =
50            reqwest_middleware::ClientBuilder::new(reqwest_client_builder.build().unwrap());
51
52        if config.enable_retry {
53            struct RetryableStatus;
54            impl reqwest_retry::RetryableStrategy for RetryableStatus {
55                fn handle(
56                    &self,
57                    res: &Result<reqwest::Response, reqwest_middleware::Error>,
58                ) -> Option<reqwest_retry::Retryable> {
59                    match res {
60                        Ok(success) => reqwest_retry::default_on_request_success(success),
61                        Err(_) => None,
62                    }
63                }
64            }
65            let backoff_policy = reqwest_retry::policies::ExponentialBackoff::builder()
66                .build_with_max_retries(config.max_retries);
67
68            let retry_middleware =
69                reqwest_retry::RetryTransientMiddleware::new_with_policy_and_strategy(
70                    backoff_policy,
71                    RetryableStatus,
72                );
73
74            middleware_client_builder = middleware_client_builder.with(retry_middleware);
75        }
76
77        let client = middleware_client_builder.build();
78
79        Self { config, client }
80    }
81
82    pub fn with_client_and_config(
83        config: datadog::Configuration,
84        client: reqwest_middleware::ClientWithMiddleware,
85    ) -> Self {
86        Self { config, client }
87    }
88
89    /// Check if the API key (not the APP key) is valid. If invalid, a 403 is returned.
90    pub async fn validate(
91        &self,
92    ) -> Result<
93        crate::datadogV1::model::AuthenticationValidationResponse,
94        datadog::Error<ValidateError>,
95    > {
96        match self.validate_with_http_info().await {
97            Ok(response_content) => {
98                if let Some(e) = response_content.entity {
99                    Ok(e)
100                } else {
101                    Err(datadog::Error::Serde(serde::de::Error::custom(
102                        "response content was None",
103                    )))
104                }
105            }
106            Err(err) => Err(err),
107        }
108    }
109
110    /// Check if the API key (not the APP key) is valid. If invalid, a 403 is returned.
111    pub async fn validate_with_http_info(
112        &self,
113    ) -> Result<
114        datadog::ResponseContent<crate::datadogV1::model::AuthenticationValidationResponse>,
115        datadog::Error<ValidateError>,
116    > {
117        let local_configuration = &self.config;
118        let operation_id = "v1.validate";
119
120        let local_client = &self.client;
121
122        let local_uri_str = format!(
123            "{}/api/v1/validate",
124            local_configuration.get_operation_host(operation_id)
125        );
126        let mut local_req_builder =
127            local_client.request(reqwest::Method::GET, local_uri_str.as_str());
128
129        // build headers
130        let mut headers = HeaderMap::new();
131        headers.insert("Accept", HeaderValue::from_static("application/json"));
132
133        // build user agent
134        match HeaderValue::from_str(local_configuration.user_agent.as_str()) {
135            Ok(user_agent) => headers.insert(reqwest::header::USER_AGENT, user_agent),
136            Err(e) => {
137                log::warn!("Failed to parse user agent header: {e}, falling back to default");
138                headers.insert(
139                    reqwest::header::USER_AGENT,
140                    HeaderValue::from_static(datadog::DEFAULT_USER_AGENT.as_str()),
141                )
142            }
143        };
144
145        // build auth
146        if let Some(local_key) = local_configuration.auth_keys.get("apiKeyAuth") {
147            headers.insert(
148                "DD-API-KEY",
149                HeaderValue::from_str(local_key.key.as_str())
150                    .expect("failed to parse DD-API-KEY header"),
151            );
152        };
153
154        local_req_builder = local_req_builder.headers(headers);
155        let local_req = local_req_builder.build()?;
156        log::debug!("request content: {:?}", local_req.body());
157        let local_resp = local_client.execute(local_req).await?;
158
159        let local_status = local_resp.status();
160        let local_content = local_resp.text().await?;
161        log::debug!("response content: {}", local_content);
162
163        if !local_status.is_client_error() && !local_status.is_server_error() {
164            match serde_json::from_str::<crate::datadogV1::model::AuthenticationValidationResponse>(
165                &local_content,
166            ) {
167                Ok(e) => {
168                    return Ok(datadog::ResponseContent {
169                        status: local_status,
170                        content: local_content,
171                        entity: Some(e),
172                    })
173                }
174                Err(e) => return Err(datadog::Error::Serde(e)),
175            };
176        } else {
177            let local_entity: Option<ValidateError> = serde_json::from_str(&local_content).ok();
178            let local_error = datadog::ResponseContent {
179                status: local_status,
180                content: local_content,
181                entity: local_entity,
182            };
183            Err(datadog::Error::ResponseError(local_error))
184        }
185    }
186}