Skip to main content

dagger_sdk/core/
graphql_client.rs

1use std::collections::HashMap;
2use std::sync::Arc;
3
4use async_trait::async_trait;
5use base64::engine::general_purpose;
6use base64::Engine;
7use thiserror::Error;
8
9use crate::core::connect_params::ConnectParams;
10use crate::core::gql_client::{ClientConfig, GQLClient};
11
12use super::config;
13use super::gql_client::GraphQLErrorMessage;
14
15#[async_trait]
16pub trait GraphQLClient {
17    async fn query(&self, query: &str) -> Result<Option<serde_json::Value>, GraphQLError>;
18}
19
20pub type DynGraphQLClient = Arc<dyn GraphQLClient + Send + Sync>;
21
22#[derive(Debug)]
23pub struct DefaultGraphQLClient {
24    client: GQLClient,
25}
26
27impl DefaultGraphQLClient {
28    pub fn new(conn: &ConnectParams, config: &config::Config) -> Self {
29        let token = general_purpose::URL_SAFE.encode(format!("{}:", conn.session_token));
30
31        let mut headers = HashMap::new();
32        headers.insert("Authorization".to_string(), format!("Basic {}", token));
33
34        Self {
35            client: GQLClient::new_with_config(ClientConfig {
36                endpoint: conn.url(),
37                connect_timeout_ms: Some(config.timeout_ms),
38                execute_timeout_ms: config.execute_timeout_ms,
39                headers: Some(headers),
40                proxy: None,
41            }),
42        }
43    }
44}
45
46#[async_trait]
47impl GraphQLClient for DefaultGraphQLClient {
48    async fn query(&self, query: &str) -> Result<Option<serde_json::Value>, GraphQLError> {
49        let res: Option<serde_json::Value> =
50            self.client.query(query).await.map_err(map_graphql_error)?;
51
52        return Ok(res);
53    }
54}
55
56fn map_graphql_error(gql_error: crate::core::gql_client::GraphQLError) -> GraphQLError {
57    let Some(json) = gql_error.json() else {
58        return GraphQLError::HttpError(gql_error.message().to_string());
59    };
60
61    let Some(message) = json.first().map(|f| f.message.clone()) else {
62        return GraphQLError::HttpError(gql_error.message().to_string());
63    };
64
65    GraphQLError::DomainError {
66        message,
67        fields: json,
68    }
69}
70
71#[derive(Error, Debug)]
72pub enum GraphQLError {
73    #[error("http error: {0}")]
74    HttpError(String),
75    #[error("domain error: {message}")]
76    DomainError {
77        message: String,
78        fields: Vec<GraphQLErrorMessage>,
79    },
80}