canic_core/ops/ic/
http.rs

1pub use crate::cdk::mgmt::{HttpHeader, HttpMethod, HttpRequestResult};
2
3use crate::{
4    Error,
5    cdk::mgmt::{HttpRequestArgs, http_request},
6    model::metrics::{
7        http::HttpMetrics,
8        system::{SystemMetricKind, SystemMetrics},
9    },
10};
11use num_traits::ToPrimitive;
12use serde::de::DeserializeOwned;
13
14///
15/// Http
16///
17
18pub struct Http;
19
20impl Http {
21    pub const MAX_RESPONSE_BYTES: u64 = 200_000;
22
23    fn record_metrics(verb: &'static str, url: &str, label: Option<&str>) {
24        SystemMetrics::increment(SystemMetricKind::HttpOutcall);
25        HttpMetrics::increment_with_label(verb, url, label);
26    }
27
28    pub async fn get<T: DeserializeOwned>(
29        url: &str,
30        headers: impl AsRef<[(&str, &str)]>,
31    ) -> Result<T, Error> {
32        Self::get_with_label(url, headers, None).await
33    }
34
35    pub async fn get_with_label<T: DeserializeOwned>(
36        url: &str,
37        headers: impl AsRef<[(&str, &str)]>,
38        label: Option<&str>,
39    ) -> Result<T, Error> {
40        // metrics
41        Self::record_metrics("GET", url, label);
42
43        let headers: Vec<HttpHeader> = headers
44            .as_ref()
45            .iter()
46            .map(|(name, value)| HttpHeader {
47                name: name.to_string(),
48                value: value.to_string(),
49            })
50            .collect();
51
52        let args = HttpRequestArgs {
53            url: url.to_string(),
54            method: HttpMethod::GET,
55            headers,
56            max_response_bytes: Some(Self::MAX_RESPONSE_BYTES),
57            ..Default::default()
58        };
59
60        let res = http_request(&args)
61            .await
62            .map_err(|e| Error::HttpRequest(e.to_string()))?;
63
64        let status: u32 = res.status.0.to_u32().unwrap_or(0);
65        if status != 200 {
66            return Err(Error::HttpErrorCode(status));
67        }
68
69        serde_json::from_slice(&res.body).map_err(Into::into)
70    }
71
72    pub async fn get_raw<T: DeserializeOwned>(
73        args: HttpRequestArgs,
74    ) -> Result<HttpRequestResult, Error> {
75        Self::get_raw_with_label(args, None).await
76    }
77
78    pub async fn get_raw_with_label(
79        args: HttpRequestArgs,
80        label: Option<&str>,
81    ) -> Result<HttpRequestResult, Error> {
82        // metrics
83        Self::record_metrics("GET", &args.url, label);
84
85        http_request(&args)
86            .await
87            .map_err(|e| crate::Error::HttpRequest(e.to_string()))
88    }
89}