Code Generation with GraphQL
One of the major benefits of using our GraphQL API is that you should not need to write your own code to interact with it. You should only need to write .graphql files that reflect exactly what data you want to query or mutate, run the GraphQL code generation tool in your language, then use as if our service was part of your own application, complete with strongly typed functions, enums, interfaces/structs/classes, etc…
The following provides examples in popular languages of how to do this.
TypeScript Setup
Section titled “TypeScript Setup”The following example uses Bun as the bundler & runtime environment.
-
Start a new project and install dependencies
#!/bin/bashmkdir example && cd examplebun init# Runtime dependenciesbun add @apollo/client# Development dependenciesbun add @graphql-codegen/cli @graphql-codegen/near-operation-file-preset --dev -
Setup codegen configuration
We will create a codegen file with some configuration for how we want to generate the code.
./codegen.ts import type { CodegenConfig } from "@graphql-codegen/cli";const config: CodegenConfig = {overwrite: true,schema: "https://api.helioadditive.com/graphql"documents: "./**/*.graphql",generates: {"types.generated.ts": {plugins: ["typescript"],config: {useInterface: true,useTypeImports: false,declarationKind: {input: "interface",},},},".": {preset: "near-operation-file",presetConfig: {extension: ".generated.ts",baseTypesPath: "types.generated.ts",},plugins: ["typescript-operations", "typed-document-node"],config: {useTypeImports: false,declarationKind: {input: "interface",},},},},};export default config; -
Create a graphql file to query data
You choose what data you want to fetch
./queries/Materials.graphql query ListMaterials($page: Int, $pageSize: Int, $filters: [MaterialFilter!]) {materials(page: $page, pageSize: $pageSize, filters: $filters) {pagespageInfo {hasPreviousPagehasNextPage}objects {... on Material {idnamebrand {idname}}}}} -
Autogenerate files
Add a new script to your
package.jsonto run the codegen tool../package.json {"name": "example","version": "0.1.0","scripts": {..."codegen": "graphql-codegen --config codegen.ts"},And then run it:
Terminal window bun run codegen -
Create a client
Apollo provides a lot of tooling for GraphQL in TypeScript. We simply leverage their client & configure it as needed.
./ApolloClient.ts import { ApolloClient, InMemoryCache, HttpLink } from "@apollo/client";export const apolloClient = new ApolloClient({uri: "https://api.helioadditive.com/graphql",cache: new InMemoryCache(),link: new HttpLink({uri: "https://api.helioadditive.com/graphql",headers: {"Content-Type": "application/json",Authorization: "Bearer <pat-token>" // The users PAT token should be dynamically inserted here},credentials: "include",fetchOptions: { cache: "no-store" },}),}); -
Utilize the generated code
In any application code, you now need only import the client and pass the automatic generated
Documentfrom a.generated.tsdocument../main.ts import { apolloClient } from "@/ApolloClient";import { MaterialsDocument } from "./queries/Materials.generated";// Construct a queryconst query = await apolloClient.query({query: MaterialsDocument,variables: {pageSize: 20,page: 1},fetchPolicy: "no-cache",});// The following is all strongly typedfor (const material of materials.data.materials.objects) {console.log(`Material ID: ${material.id}, Name: ${material.name}`);}
Python Setup
Section titled “Python Setup”-
Start a new project and install dependencies
uvis a modern Python package manager:#!/bin/bashmkdir example && cd exampleuv inituv add ariadne-codegen # GraphQL codegen tool -
Setup codegen configuration
Update the
pyproject.tomlfile to specify settings for autogenerated code../pyproject.toml [project]name = "example"version = "0.1.0"description = "Add your description here"readme = "README.md"requires-python = ">=3.13"dependencies = ["ariadne-codegen>=0.14.0",][tool.ariadne-codegen]target_package_path = "./client"queries_path = "./queries"remote_schema_url = "https://api.helioadditive.com/graphql"target_package_name = "graphql_client"async_client = trueinclude_comments = "stable"convert_to_snake_case = trueinclude_all_inputs = trueinclude_all_emums = true -
Create a graphql file to query data
You choose what data you want to receive
./queries/Materials.graphql query ListMaterials($page: Int, $pageSize: Int, $filters: [MaterialFilter!]) {materials(page: $page, pageSize: $pageSize, filters: $filters) {pagespageInfo {hasPreviousPagehasNextPage}objects {... on Material {idnamebrand {idname}}}}} -
Autogenerate the code
Terminal window uv run ariadne-codegen --config pyproject.tomlAll generated code should now be generated in the
./clientdirectory -
Update the
main.pyto use the generated codeNotice that there is no logic to handle the requests, that logic is already autogeneratd and baked into functions like
materials./main.py import asyncioimport httpxfrom client.client import clientheaders = {"Authorization": "Bearer <helio_pat>"}graphql_client = Client(url="https://api.helioadditive.com/graphql",headers=headers,http_client=httpx.AsyncClient(headers=headers, timeout=60))async def main():materials = await graphql_client.materials(page_size=20)for material in materials.objects:# The `material` object is fully type inferredmaterial_id = material.idmaterial_name = material.nameif __name__ == "__main__":asyncio.run(main()) -
Next steps
You can now add any
.graphqlfiles you need into thequeriesdirectory, re-run the codegen tool, and start using it directly in the code.
Rust Setup
Section titled “Rust Setup”The following example uses graphql-client for compile-time code generation.
-
Start a new project and install dependencies
Create a new Rust project and add dependencies:
#!/bin/bashcargo new example && cd exampleAdd dependencies to
Cargo.toml:./Cargo.toml [package]name = "example"version = "0.1.0"edition = "2021"[dependencies]graphql_client = "0.14"reqwest = { version = "0.12", features = ["json"] }serde = { version = "1.0", features = ["derive"] }serde_json = "1.0"tokio = { version = "1", features = ["full"] } -
Download the GraphQL schema
Terminal window curl https://helioadditive-public.s3.ap-east-1.amazonaws.com/docs/schema.graphqls -o schema.graphqls -
Create a graphql file to query data
Create a queries directory and add your query:
./queries/materials.graphql query ListMaterials($page: Int, $pageSize: Int, $filters: [MaterialFilter!]) {materials(page: $page, pageSize: $pageSize, filters: $filters) {pagespageInfo {hasPreviousPagehasNextPage}objects {... on Material {idnamebrand {idname}}}}} -
Use the graphql_client macro
The
graphql_clientcrate uses Rust’s procedural macros to generate code at compile time rather than generated actual files:./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 ListMaterials;#[tokio::main]async fn main() -> Result<(), Box<dyn std::error::Error>> {let pat_token = std::env::var("PAT").expect("PAT environment variable must be set");let client = reqwest::Client::new();let variables = list_materials::Variables {page: Some(1),page_size: Some(5),filters: None,};let response = client.post("https://api.helioadditive.com/graphql").header(CONTENT_TYPE, "application/json").header(AUTHORIZATION, format!("Bearer {}", pat_token)).json(&ListMaterials::build_query(variables)).send().await?;let body: Response<list_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");println!("Fetched {} pages of materials", data.materials.pages);println!("Has next page: {}", data.materials.page_info.has_next_page);for material in data.materials.objects {println!("\nMaterial: {} (ID: {})", material.name, material.id);if let Some(brand) = &material.brand {println!(" Brand: {} (ID: {})", brand.name, brand.id);}}Ok(())} -
Run the application
Terminal window cargo run
C++ Setup
Section titled “C++ Setup”-
Start a new project and install dependencies
Create project Setup
vcpkgin the example#!/bin/bashmkdir example && cd example -
Setup
vcpkg& install dependenciesCreate the
vcpkg.jsonfile:./vcpkg.json {"name": "example","version-string": "0.0.1","builtin-baseline": "095a29ce59608465032c3747307dd0009b3e089c","dependencies": [{"name": "pegtl","version>=": "3.2.8"},{"name": "cppgraphqlgen","version>=": "4.5.7","features": ["clientgen", "rapidjson"]},{"name": "boost-json","version>=": "1.88.0"},{"name": "cpr","version>=": "1.11.2"}]}And then setup / install:
Terminal window git submodule add https://github.com/microsoft/vcpkg./vcpkg/bootstrap-vcpkg.sh./vcpkg/vcpkg install -
Create a graphql file to query data
You choose what data you want to fetch
./queries/Materials.graphql query ListMaterials($page: Int, $pageSize: Int, $filters: [MaterialFilter!]) {materials(page: $page, pageSize: $pageSize, filters: $filters) {pagespageInfo {hasPreviousPagehasNextPage}objects {... on Material {idnamebrand {idname}}}}} -
Autogenerate the code
clientgenallows us to autogenerated all of the functions, structs and enums needed to handle our query files. This means we don’t need to write any manual requests with possible incorrect types, just call the function as if it were part of the library itself.Terminal window mkdir -p ./generated/srcmkdir -p ./generated/includecurl https://api.helioadditive.com/graphql/scehma -o schema.graphqls./vcpkg/packages/cppgraphqlgen_arm64-osx/tools/cppgraphqlgen/clientgen \--schema ./schema.graphqls \--request queries/Materials.graphql \--namespace HelioAdditive \--prefix Materials \--source-dir ./generated/src \--header-dir ./generated/include -
Create the
main.cppapp entrypointAll of the structs, enums and functions to handle all types to/from our API are already autogenerated including the serialization logic. This means you can now write interact with our API with 100% type confidence.
./src/main.cpp #include <iostream>#include <string>#include "MaterialsClient.h"#include "graphqlservice/GraphQLResponse.h"#include "graphqlservice/JSONResponse.h"namespace Materials = graphql::client::query::Materials;int main() {const std::string query = Materials::GetRequestText();graphql::response::Value variables = Materials::serializeVariables(Materials::Variables{.pageSize = 20, .page = 1});auto parsed_response = Materials::parseResponse(sendHttpRequest(query, variables));for (const auto &material : parsed_response.materials.objects) {std::cout << "Material ID: " << material.id.c_str() << ", Name: " << material.name << '\n';}return 0;}NOTE: C++ autogenerated GraphQL code does not include logic to handle the HTTP requests like in other languages, as such an example function of how to handle the HTTP requests is shown below with
cpr, but one could easily useboostorlibcurlbased on what is used in your project:#include <cpr/cpr.h>#include <boost/json.hpp>graphql::response::Value sendHttpRequest(const std::string &query, graphql::response::Value &variables) {std::string body = boost::json::serialize(boost::json::object{{"query", query},{"variables", boost::json::parse(graphql::response::toJSON(std::move(variables))).as_object()}});return graphql::response::parseJSON(boost::json::serialize(boost::json::parse(cpr::Post(cpr::Url{"https://api.helioadditive.com/graphql"},cpr::Header{{"Content-Type", "application/json"}, {"Authorization", "Bearer <pat_token>"}},cpr::Body{body}).text).as_object()["data"].as_object()));} -
Build
C++ is an advanced language and every build system is different. For below example shows how one could use CMake to build:
cmake_minimum_required(VERSION 3.14)project(ExampleApp)set(CMAKE_CXX_STANDARD 20)set(CMAKE_CXX_FLAGS "-std=c++20 -O3 ")include_directories(${VCPKG_DIR}/include)link_directories(${VCPKG_DIR}/lib)FIND_PACKAGE(CURL)find_package(Boost REQUIRED COMPONENTS json)find_package(cppgraphqlgen 4.5.7 CONFIG REQUIRED)find_package(cpr 1.11.1 REQUIRED)include_directories(generated/include)file(GLOB_RECURSE GENERATED_SRC "generated/src/*.cpp")file(GLOB_RECURSE GENERATED_HEADERS "generated/include/*.h")add_executable(ExampleApp src/main.cpp ${GENERATED_SRC})include_directories({CURL_INCLUDE_DIRS})target_link_libraries(ExampleAppPRIVATEcppgraphqlgen::graphqlservicecppgraphqlgen::graphqlclientcppgraphqlgen::graphqlresponsecppgraphqlgen::graphqlpegcppgraphqlgen::graphqlcorocppgraphqlgen::graphqljsontaocpp::pegtlcpr::cprBoost::json)target_include_directories(ExampleAppPUBLIC$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/generated>$<INSTALL_INTERFACE:generated/include>PRIVATE${VCPKG_DIR}/include)