canic_core/ops/
http.rs

1use crate::{
2    Error,
3    cdk::mgmt::{HttpHeader, HttpMethod, HttpRequestArgs, http_request},
4    model::metrics::{HttpMetrics, SystemMetricKind, SystemMetrics},
5};
6use num_traits::ToPrimitive;
7use serde::de::DeserializeOwned;
8
9const MAX_RESPONSE_BYTES: u64 = 200_000;
10
11///
12/// http_get
13/// Generic helper for HTTP GET with JSON response.
14pub async fn http_get<T: DeserializeOwned>(
15    url: &str,
16    headers: &[(String, String)],
17) -> Result<T, Error> {
18    // record metrics up front so attempts are counted
19    SystemMetrics::increment(SystemMetricKind::HttpOutcall);
20    HttpMetrics::increment("GET", url);
21
22    let headers: Vec<HttpHeader> = headers
23        .iter()
24        .map(|(name, value)| HttpHeader {
25            name: name.clone(),
26            value: value.clone(),
27        })
28        .collect();
29
30    let args = HttpRequestArgs {
31        url: url.to_string(),
32        method: HttpMethod::GET,
33        headers,
34        max_response_bytes: Some(MAX_RESPONSE_BYTES),
35        ..Default::default()
36    };
37
38    let res = http_request(&args)
39        .await
40        .map_err(|e| Error::HttpRequest(e.to_string()))?;
41
42    // status
43    let status: u32 = res.status.0.to_u32().unwrap_or(0);
44    if status != 200 {
45        return Err(Error::HttpErrorCode(status));
46    }
47
48    // deserialize json
49    let res: T = serde_json::from_slice::<T>(&res.body)?;
50
51    Ok(res)
52}