Introduction: Why GraphQL and C++ is a Powerful Combination
GraphQL has become a standard for modern APIs, offering flexibility and efficiency compared to REST. But how do you implement it in C++ — a language known for its performance and strictness? In this tutorial, we will walk through creating a full-fledged GraphQL API in C++ using the cppgraphqlgen library. You will learn how to define a schema, write resolvers, handle queries and mutations. The code examples will be practical so you can immediately apply them in your projects.
By the end of this article, you will be able to create a simple but working GraphQL server in C++ that accepts requests and returns data. Let's go!
Installing and Setting Up the Environment
For this we will need:
- A compiler with C++17 support (e.g., GCC 8+ or Clang 7+)
- CMake (version 3.14+)
- The
cppgraphqlgenlibrary (code generation from a GraphQL schema) - An HTTP server (e.g.,
cpp-httplibfor simplicity)
We will install dependencies via vcpkg or build them manually. For this tutorial, we use vcpkg:
git clone https://github.com/Microsoft/vcpkg.gitcd vcpkg./bootstrap-vcpkg.sh./vcpkg install cppgraphqlgen cpp-httplibCreate the project structure:
graphql-cpp-tutorial/├── schema.graphql├── CMakeLists.txt├── src/│ ├── main.cpp│ ├── resolver.cpp│ └── resolver.hStep 1: Define the GraphQL Schema
Create a file schema.graphql with a simple schema for managing tasks (Todo):
type Query { todos: [Todo!]! todo(id: ID!): Todo}
type Mutation { addTodo(title: String!): Todo! completeTodo(id: ID!): Todo}
type Todo { id: ID! title: String! completed: Boolean!}This schema describes:
- Query — retrieving a list of tasks or a single task by ID
- Mutation — adding a new task and marking one as completed
- Type Todo — an object with fields id, title, completed
The schema is the contract of our API. Next, we will generate C++ code from it.
Step 2: Generate C++ Code from the Schema
Use the graphqlgenerategen utility from the cppgraphqlgen package:
graphqlgenerategen schema.graphql --output-dir ./generatedAfter execution, the following files will appear in the generated folder:
TodoObject.h— class for the Todo typeQueryObject.h— base class for Query resolversMutationObject.h— base class for Mutation resolversschema.h— schema integration
These files contain generated interfaces that we need to implement.
Step 3: Implement Resolvers
Create a file resolver.h with declarations:
#include "generated/QueryObject.h"#include "generated/MutationObject.h"#include <vector>#include <memory>
struct Todo { std::string id; std::string title; bool completed;};
class QueryResolver : public graphql::todo::QueryObject {public: std::vector<std::shared_ptr<graphql::todo::TodoObject>> getTodos() const override; std::shared_ptr<graphql::todo::TodoObject> getTodo(const std::string& id) const override;
private: static std::vector<Todo> todos_;};
class MutationResolver : public graphql::todo::MutationObject {public: std::shared_ptr<graphql::todo::TodoObject> applyAddTodo(const std::string& title) override; std::shared_ptr<graphql::todo::TodoObject> applyCompleteTodo(const std::string& id) override;};Now implement the logic in resolver.cpp:
#include "