use std::time::Duration;
use graphql_client::GraphQLQuery;
use reqwest::{
header::{HeaderMap, HeaderValue},
Client,
};
use crate::{commands::Environment, config::Configs, consts, errors::RailwayError};
use anyhow::Result;
use graphql_client::Response as GraphQLResponse;
pub struct GQLClient;
impl GQLClient {
pub fn new_authorized(configs: &Configs) -> Result<Client, RailwayError> {
let mut headers = HeaderMap::new();
if let Some(token) = &Configs::get_railway_token() {
headers.insert("project-access-token", HeaderValue::from_str(token)?);
} else if let Some(token) = configs.get_railway_auth_token() {
headers.insert(
"authorization",
HeaderValue::from_str(&format!("Bearer {token}"))?,
);
} else {
return Err(RailwayError::Unauthorized);
}
headers.insert(
"x-source",
HeaderValue::from_static(consts::get_user_agent()),
);
let client = Client::builder()
.danger_accept_invalid_certs(matches!(Configs::get_environment_id(), Environment::Dev))
.user_agent(consts::get_user_agent())
.default_headers(headers)
.timeout(Duration::from_secs(15))
.build()
.unwrap();
Ok(client)
}
pub fn new_unauthorized() -> Result<Client> {
let mut headers = HeaderMap::new();
headers.insert(
"x-source",
HeaderValue::from_static(consts::get_user_agent()),
);
let client = Client::builder()
.danger_accept_invalid_certs(matches!(Configs::get_environment_id(), Environment::Dev))
.user_agent(consts::get_user_agent())
.default_headers(headers)
.build()?;
Ok(client)
}
}
pub async fn post_graphql<Q: GraphQLQuery, U: reqwest::IntoUrl>(
client: &reqwest::Client,
url: U,
variables: Q::Variables,
) -> Result<Q::ResponseData, RailwayError> {
let body = Q::build_query(variables);
let res: GraphQLResponse<Q::ResponseData> =
client.post(url).json(&body).send().await?.json().await?;
if let Some(errors) = res.errors {
if errors[0].message.to_lowercase().contains("not authorized") {
Err(RailwayError::Unauthorized)
} else {
Err(RailwayError::GraphQLError(errors[0].message.clone()))
}
} else if let Some(data) = res.data {
Ok(data)
} else {
Err(RailwayError::MissingResponseData)
}
}