GraphQL Client Typed Queries Rust

Execute GraphQL queries from Rust with graphql-client, deriving response types from the query document and variables.

RustData Fetching

Code

snippet
use graphql_client::{GraphQLQuery, Response};

// queries/top_customers.graphql:
// query TopCustomers($region: Region!, $first: Int!) {
//   customers(region: $region, first: $first) {
//     edges { node { id name lifetimeValue } }
//   }
// }

#[derive(GraphQLQuery)]
#[graphql(
    query_path = "queries/top_customers.graphql",
    schema_path = "schemas/customer.graphql",
    response_derives = "Debug"
)]
pub struct TopCustomers;

type Customer = top_customers::TopCustomersCustomersEdgesNode;

async fn fetch_top_customers(
    region: &str,
    first: i64,
) -> Result<Vec<Customer>, Box<dyn std::error::Error>> {
    let variables = top_customers::Variables {
        region: region.into(),
        first,
    };

    let request_body = TopCustomers::build_query(variables);
    let client = reqwest::Client::new();

    let res = client
        .post("https://api.example.com/graphql")
        .json(&request_body)
        .send()
        .await?
        .error_for_status()?;

    let response_body: Response<top_customers::ResponseData> = res.json().await?;

    let data = response_body
        .data
        .ok_or("query returned no data")?;

    if let Some(errors) = response_body.errors {
        for err in &errors {
            eprintln!("graphql error: {:?}", err.message);
        }
    }

    let customers: Vec<Customer> = data
        .customers
        .map(|conn| {
            conn.edges
                .into_iter()
                .filter_map(|edge| edge.map(|e| e.node))
                .collect()
        })
        .unwrap_or_default();

    Ok(customers)
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let customers = fetch_top_customers("eu", 5).await?;
    for customer in customers {
        println!("{:?} value={}", customer, customer.lifetime_value);
    }
    Ok(())
}