cli/commands/internal/graphql/
run.rs1use anyhow::{anyhow, Result};
2use serde::{Deserialize, Serialize};
3use std::io::{self, Read};
4
5#[derive(Debug, clap::Args)]
6pub struct Run {
7 pub query: Option<String>,
9
10 #[arg(long, short = 'v')]
12 pub variables: Option<String>,
13
14 #[arg(long, short = 'f')]
16 pub file: Option<String>,
17
18 #[arg(long, default_value = "http://localhost:3000/graphql")]
20 pub node: String,
21}
22
23#[derive(Debug, Serialize)]
24struct GraphQLRequest {
25 query: String,
26 #[serde(skip_serializing_if = "Option::is_none")]
27 variables: Option<serde_json::Value>,
28}
29
30#[derive(Debug, Deserialize)]
31struct GraphQLResponse {
32 data: Option<serde_json::Value>,
33 errors: Option<Vec<GraphQLError>>,
34}
35
36#[derive(Debug, Deserialize)]
37struct GraphQLError {
38 message: String,
39}
40
41impl Run {
42 pub fn run(self) -> Result<()> {
43 let query = if let Some(query) = self.query {
45 query
46 } else if let Some(file_path) = self.file {
47 std::fs::read_to_string(&file_path)
48 .map_err(|e| anyhow!("Failed to read file '{}': {}", file_path, e))?
49 } else {
50 let mut buffer = String::new();
52 io::stdin()
53 .read_to_string(&mut buffer)
54 .map_err(|e| anyhow!("Failed to read from stdin: {}", e))?;
55 buffer
56 };
57
58 let variables = if let Some(vars_str) = self.variables {
60 let vars: serde_json::Value = serde_json::from_str(&vars_str)
61 .map_err(|e| anyhow!("Failed to parse variables JSON: {}", e))?;
62 Some(vars)
63 } else {
64 None
65 };
66
67 let request = GraphQLRequest { query, variables };
69
70 let client = reqwest::blocking::Client::new();
72 let response = client
73 .post(&self.node)
74 .json(&request)
75 .send()
76 .map_err(|e| anyhow!("Failed to connect to GraphQL server: {}", e))?;
77
78 if !response.status().is_success() {
79 return Err(anyhow!(
80 "GraphQL server returned error: {}",
81 response.status()
82 ));
83 }
84
85 let graphql_response: GraphQLResponse = response
86 .json()
87 .map_err(|e| anyhow!("Failed to parse GraphQL response: {}", e))?;
88
89 if let Some(errors) = &graphql_response.errors {
91 if !errors.is_empty() {
92 eprintln!("Errors:");
93 for error in errors {
94 eprintln!(" - {}", error.message);
95 }
96 if graphql_response.data.is_none() {
97 return Err(anyhow!("GraphQL query failed with errors"));
98 }
99 }
100 }
101
102 if let Some(data) = graphql_response.data {
103 let formatted = serde_json::to_string_pretty(&data)
104 .unwrap_or_else(|_| serde_json::to_string(&data).unwrap_or_default());
105 println!("{}", formatted);
106 }
107
108 Ok(())
109 }
110}