Skip to main content

runtime_cli/commands/
api.rs

1//! `runtime api '<query>'` — escape hatch for arbitrary GraphQL.
2//!
3//! Accepts an optional list of `--var key=value` pairs that compose
4//! the `variables` object. Values are parsed as JSON first; on parse
5//! failure they fall back to strings so `--var slug=alice/r1` does the
6//! intuitive thing.
7
8use std::io::Write;
9
10use anyhow::{anyhow, Result};
11use clap::Args;
12use serde_json::{json, Map, Value};
13
14use crate::client;
15
16#[derive(Debug, Args)]
17pub struct ApiArgs {
18    /// GraphQL query or mutation source.
19    pub query: String,
20    /// `key=value` variable bindings (repeat for multiple vars).
21    #[arg(long = "var", value_name = "KEY=VALUE")]
22    pub vars: Vec<String>,
23}
24
25pub fn run(args: ApiArgs) -> Result<()> {
26    let (cli, _cfg) = client::authenticated()?;
27    let mut vars = Map::new();
28    for raw in &args.vars {
29        let (k, v) = raw
30            .split_once('=')
31            .ok_or_else(|| anyhow!("expected `KEY=VALUE`, got `{raw}`"))?;
32        let parsed =
33            serde_json::from_str::<Value>(v).unwrap_or_else(|_| Value::String(v.to_string()));
34        vars.insert(k.to_string(), parsed);
35    }
36    let result = cli.execute_raw(&args.query, json!(vars))?;
37    let mut stdout = std::io::stdout().lock();
38    stdout.write_all(serde_json::to_string_pretty(&result)?.as_bytes())?;
39    stdout.write_all(b"\n")?;
40    Ok(())
41}