Listing Materials
This example demonstrates how to query and paginate through available materials in the Helio Additive platform.
GraphQL Operations
Section titled “GraphQL Operations”Create the following GraphQL query file, then run your language’s codegen tool to generate the types.
query Materials($page: Int, $pageSize: Int) { materials(page: $page, pageSize: $pageSize) { pages pageInfo { hasPreviousPage hasNextPage } objects { ... on Material { id name brand { id name } feedstock density minExtrusionTemp maxExtrusionTemp } } }}API Reference:
- Material type - Full material object structure
- Feedstock enum - Material feedstock types (Filament, Pellet)
- MaterialFilter input - Available filter options
Code Example
Section titled “Code Example”-
Setup the client and configuration
index.ts import { ApolloClient, InMemoryCache, HttpLink } from "@apollo/client";import { MaterialsDocument } from "./queries/__generated/Materials.generated";// Load PAT from environmentconst PAT = process.env.PAT;if (!PAT) {throw new Error("PAT environment variable is required");}// Create Apollo Clientconst client = new ApolloClient({cache: new InMemoryCache(),link: new HttpLink({uri: "https://api.helioadditive.com/graphql",headers: {"Content-Type": "application/json",Authorization: `Bearer ${PAT}`,},}),});main.py import asyncioimport osimport httpxfrom client.client import Client# Load PAT from environmentPAT = os.environ.get("PAT")if not PAT:raise ValueError("PAT environment variable is required")# Create GraphQL clientheaders = {"Authorization": f"Bearer {PAT}"}graphql_client = Client(url="https://api.helioadditive.com/graphql",headers=headers,http_client=httpx.AsyncClient(headers=headers, timeout=60))src/main.rs use graphql_client::{GraphQLQuery, Response};use reqwest::header::{AUTHORIZATION, CONTENT_TYPE};#[derive(GraphQLQuery)]#[graphql(schema_path = "schema.graphqls",query_path = "queries/Materials.graphql",response_derives = "Debug")]struct Materials;// Load from environment in main()let pat = std::env::var("PAT").expect("PAT environment variable must be set");src/main.cpp #include <iostream>#include <string>#include <cstdlib>#include <cpr/cpr.h>#include <boost/json.hpp>#include "MaterialsClient.h"#include "graphqlservice/GraphQLResponse.h"#include "graphqlservice/JSONResponse.h"namespace Materials = graphql::client::query::Materials;// Helper function to send HTTP requestsgraphql::response::Value sendHttpRequest(const std::string& query,graphql::response::Value& variables,const std::string& pat) {std::string body = boost::json::serialize(boost::json::object{{"query", query},{"variables", boost::json::parse(graphql::response::toJSON(std::move(variables))).as_object()}});auto response = cpr::Post(cpr::Url{"https://api.helioadditive.com/graphql"},cpr::Header{{"Content-Type", "application/json"},{"Authorization", "Bearer " + pat}},cpr::Body{body});return graphql::response::parseJSON(boost::json::serialize(boost::json::parse(response.text).as_object()["data"].as_object()));}// Load PAT from environmentconst char* pat_env = std::getenv("PAT");if (!pat_env) {std::cerr << "PAT environment variable is required" << std::endl;return 1;}std::string pat(pat_env); -
Query and paginate through materials
Fetch materials page by page until all materials have been retrieved.
async function listMaterials() {let page = 1;const pageSize = 20;const allMaterials: Array<{ id: string; name: string }> = [];// Paginate through all materialswhile (true) {const { data } = await client.query({query: MaterialsDocument,variables: { page, pageSize },fetchPolicy: "no-cache",});// Collect materials from this pagefor (const material of data?.materials?.objects ?? []) {if (material.__typename === "Material") {allMaterials.push({id: material.id,name: material.name,});console.log(`Material: ${material.name} (${material.brand?.name})`);}}// Check if there are more pagesif (!data?.materials?.pageInfo?.hasNextPage) {break;}page++;}return allMaterials;}async def list_materials():page = 1page_size = 20all_materials = []# Paginate through all materialswhile True:result = await graphql_client.materials(page=page, page_size=page_size)# Collect materials from this pagefor material in result.objects:all_materials.append({"id": material.id,"name": material.name,})brand_name = material.brand.name if material.brand else "Unknown"print(f"Material: {material.name} ({brand_name})")# Check if there are more pagesif not result.page_info.has_next_page:breakpage += 1return all_materialsasync fn list_materials(pat: &str) -> Result<Vec<(String, String)>, Box<dyn std::error::Error>> {let client = reqwest::Client::new();let mut page = 1;let page_size = 20;let mut all_materials: Vec<(String, String)> = Vec::new();// Paginate through all materialsloop {let variables = materials::Variables {page: Some(page as i64),page_size: Some(page_size),};let response = client.post("https://api.helioadditive.com/graphql").header(CONTENT_TYPE, "application/json").header(AUTHORIZATION, format!("Bearer {}", pat)).json(&Materials::build_query(variables)).send().await?;let body: Response<materials::ResponseData> = response.json().await?;if let Some(errors) = body.errors {return Err(format!("GraphQL errors: {:?}", errors).into());}let data = body.data.expect("No data returned");// Collect materials from this pagefor material in &data.materials.objects {let brand_name = material.brand.as_ref().map(|b| b.name.as_str()).unwrap_or("Unknown");println!("Material: {} ({})", material.name, brand_name);all_materials.push((material.id.clone(), material.name.clone()));}// Check if there are more pagesif !data.materials.page_info.has_next_page {break;}page += 1;}Ok(all_materials)}struct MaterialInfo {std::string id;std::string name;};std::vector<MaterialInfo> listMaterials(const std::string& pat) {int page = 1;const int pageSize = 20;std::vector<MaterialInfo> allMaterials;// Paginate through all materialswhile (true) {const std::string query = Materials::GetRequestText();graphql::response::Value variables = Materials::serializeVariables(Materials::Variables{.page = page, .pageSize = pageSize});auto response = Materials::parseResponse(sendHttpRequest(query, variables, pat));// Collect materials from this pagefor (const auto& material : response.materials.objects) {allMaterials.push_back({material.id, material.name});std::string brandName = material.brand ? material.brand->name : "Unknown";std::cout << "Material: " << material.name << " (" << brandName << ")" << std::endl;}// Check if there are more pagesif (!response.materials.pageInfo.hasNextPage) {break;}page++;}return allMaterials;} -
Put it all together
Run the function and display the results.
// Example usagelistMaterials().then((materials) => {console.log(`\nTotal materials found: ${materials.length}`);}).catch(console.error);if __name__ == "__main__":async def main():materials = await list_materials()print(f"\nTotal materials found: {len(materials)}")asyncio.run(main())#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> {let pat = std::env::var("PAT").expect("PAT environment variable must be set");let materials = list_materials(&pat).await?;println!("\nTotal materials found: {}", materials.len());Ok(())}int main() {const char* pat_env = std::getenv("PAT");if (!pat_env) {std::cerr << "PAT environment variable is required" << std::endl;return 1;}std::string pat(pat_env);auto materials = listMaterials(pat);std::cout << "\nTotal materials found: " << materials.size() << std::endl;return 0;}
Running the Example
Section titled “Running the Example”-
Create a
.env.localfile with your PAT:Terminal window PAT="your-personal-access-token" -
Run the example:
Terminal window bun run index.tsTerminal window uv run main.pyTerminal window cargo runTerminal window mkdir build && cd buildcmake .. -DVCPKG_DIR=$(pwd)/../vcpkg/installed/arm64-osxmake./ExampleApp