canic_core/ops/ic/
http.rs

1pub use crate::cdk::mgmt::{HttpHeader, HttpMethod, HttpRequestArgs, HttpRequestResult};
2
3use crate::{
4    Error,
5    cdk::mgmt::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(method: HttpMethod, url: &str, label: Option<&str>) {
24        SystemMetrics::increment(SystemMetricKind::HttpOutcall);
25        HttpMetrics::increment_with_label(method, 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(HttpMethod::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 !(200..300).contains(&status) {
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(args: HttpRequestArgs) -> Result<HttpRequestResult, Error> {
73        Self::get_raw_with_label(args, None).await
74    }
75
76    pub async fn get_raw_with_label(
77        args: HttpRequestArgs,
78        label: Option<&str>,
79    ) -> Result<HttpRequestResult, Error> {
80        // metrics
81        Self::record_metrics(args.method, &args.url, label);
82
83        http_request(&args)
84            .await
85            .map_err(|e| crate::Error::HttpRequest(e.to_string()))
86    }
87}