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
12#[async_trait]
13pub trait GraphQLClient {
14    async fn query(&self, query: &str) -> Result<Option<serde_json::Value>, GraphQLError>;
15}
16
17pub type DynGraphQLClient = Arc<dyn GraphQLClient + Send + Sync>;
18
19#[derive(Debug)]
20pub struct DefaultGraphQLClient {
21    client: GQLClient,
22}
23
24impl DefaultGraphQLClient {
25    pub fn new(conn: &ConnectParams) -> Self {
26        let token = general_purpose::URL_SAFE.encode(format!("{}:", conn.session_token));
27
28        let mut headers = HashMap::new();
29        headers.insert("Authorization".to_string(), format!("Basic {}", token));
30
31        Self {
32            client: GQLClient::new_with_config(ClientConfig {
33                endpoint: conn.url(),
34                timeout: Some(1000),
35                headers: Some(headers),
36                proxy: None,
37            }),
38        }
39    }
40}
41
42#[async_trait]
43impl GraphQLClient for DefaultGraphQLClient {
44    async fn query(&self, query: &str) -> Result<Option<serde_json::Value>, GraphQLError> {
45        let res: Option<serde_json::Value> =
46            self.client.query(query).await.map_err(map_graphql_error)?;
47
48        return Ok(res);
49    }
50}
51
52fn map_graphql_error(gql_error: crate::core::gql_client::GraphQLError) -> GraphQLError {
53    let message = gql_error.message().to_string();
54    let json = gql_error.json();
55
56    if let Some(json) = json {
57        if !json.is_empty() {
58            return GraphQLError::DomainError {
59                message,
60                fields: GraphqlErrorMessages(json.into_iter().map(|e| e.message).collect()),
61            };
62        }
63    }
64
65    GraphQLError::HttpError(message)
66}
67
68#[derive(Error, Debug)]
69pub enum GraphQLError {
70    #[error("http error: {0}")]
71    HttpError(String),
72    #[error("domain error:\n{message}\n{fields}")]
73    DomainError {
74        message: String,
75        fields: GraphqlErrorMessages,
76    },
77}
78
79#[derive(Debug, Clone)]
80pub struct GraphqlErrorMessages(Vec<String>);
81
82impl std::fmt::Display for GraphqlErrorMessages {
83    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84        for error in self.0.iter() {
85            f.write_fmt(format_args!("{error}\n"))?;
86        }
87
88        Ok(())
89    }
90}