Skip to content

C++ example using our API

Our API uses GraphQL, below is an example of how to leverage GraphQL’s automatic code generation to work with our services as if it were part of your application itself.

  1. Start a new project and install dependencies

    Create project Setup vcpkg in the example

    #!/bin/bash
    mkdir example && cd example
  2. Setup vcpkg & install dependencies

    Create the vcpkg.json file:

    ./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
  3. 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) {
    pages
    pageInfo {
    hasPreviousPage
    hasNextPage
    }
    objects {
    ... on Material {
    id
    name
    brand {
    id
    name
    }
    }
    }
    }
    }
  4. Autogenerate the code

    clientgen allows 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/src
    mkdir -p ./generated/include
    curl 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
  5. Create the main.cpp app entrypoint

    All 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 use boost or libcurl based 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()));
    }
  6. 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(ExampleApp
    PRIVATE
    cppgraphqlgen::graphqlservice
    cppgraphqlgen::graphqlclient
    cppgraphqlgen::graphqlresponse
    cppgraphqlgen::graphqlpeg
    cppgraphqlgen::graphqlcoro
    cppgraphqlgen::graphqljson
    taocpp::pegtl
    cpr::cpr
    Boost::json
    )
    target_include_directories(ExampleApp
    PUBLIC
    $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/generated>
    $<INSTALL_INTERFACE:generated/include>
    PRIVATE
    ${VCPKG_DIR}/include
    )