1use anyhow::{Result, anyhow};
2use cynic::http::ReqwestExt;
3use reqwest::Client;
4
5pub struct LinearClient {
6 client: Client,
7 url: String,
8 api_key: String,
9}
10
11impl LinearClient {
12 pub fn new(api_key: Option<String>) -> Result<Self> {
13 let api_key = match api_key.or_else(|| std::env::var("LINEAR_API_KEY").ok()) {
14 Some(k) if !k.is_empty() => k,
15 _ => return Err(anyhow!("LINEAR_API_KEY environment variable is not set")),
16 };
17
18 let url = std::env::var("LINEAR_GRAPHQL_URL")
19 .ok()
20 .filter(|u| !u.is_empty())
21 .unwrap_or_else(|| "https://api.linear.app/graphql".to_string());
22
23 let client = Client::builder().user_agent("linear-tools/0.1.0").build()?;
24
25 Ok(Self {
26 client,
27 url,
28 api_key,
29 })
30 }
31
32 pub async fn run<Q, V>(&self, op: cynic::Operation<Q, V>) -> Result<cynic::GraphQlResponse<Q>>
33 where
34 Q: serde::de::DeserializeOwned + 'static,
35 V: serde::Serialize,
36 {
37 let mut req = self
38 .client
39 .post(&self.url)
40 .header("Content-Type", "application/json");
41
42 if self.api_key.starts_with("lin_api_") {
46 req = req.header("Authorization", &self.api_key);
47 } else {
48 req = req.bearer_auth(&self.api_key);
49 }
50
51 let result = req.run_graphql(op).await;
52 result.map_err(|e| anyhow!(e))
53 }
54}