GraphQL API на C++: пошаговый туториал для начинающих

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: Почему GraphQL и C++ — это мощная комбинация

GraphQL стал стандартом для современных API, предлагая гибкость и эффективность по сравнению с REST. Но как реализовать его на C++ — языке, известном своей производительностью и строгостью? В этом туториале мы разберем создание полноценного GraphQL API на C++ с использованием библиотеки cppgraphqlgen. Вы узнаете, как определить схему, написать резолверы, обработать запросы и мутации. Примеры кода будут практическими, чтобы вы могли сразу применить их в своих проектах.

К концу статьи вы сможете создать простой, но рабочий GraphQL сервер на C++, который принимает запросы и возвращает данные. Поехали!

Установка и настройка окружения

Для работы нам понадобятся:

  • Компилятор с поддержкой C++17 (например, GCC 8+ или Clang 7+)
  • CMake (версия 3.14+)
  • Библиотека cppgraphqlgen (генерация кода из схемы GraphQL)
  • HTTP-сервер (например, cpp-httplib для простоты)

Установим зависимости через vcpkg или соберем вручную. Для этого туториала мы используем vcpkg:

git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg install cppgraphqlgen cpp-httplib

Создадим структуру проекта:

graphql-cpp-tutorial/
├── schema.graphql
├── CMakeLists.txt
├── src/
│   ├── main.cpp
│   ├── resolver.cpp
│   └── resolver.h

Шаг 1: Определяем GraphQL-схему

Создадим файл schema.graphql с простой схемой для управления задачами (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!
}

Эта схема описывает:

  • Query — получение списка задач или одной задачи по ID
  • Mutation — добавление новой задачи и отметка выполненной
  • Type Todo — объект с полями id, title, completed

Схема — это контракт нашего API. Далее мы сгенерируем из нее C++ код.

Шаг 2: Генерация C++ кода из схемы

Используем утилиту graphqlgenerategen из пакета cppgraphqlgen:

graphqlgenerategen schema.graphql --output-dir ./generated

После выполнения в папке generated появятся файлы:

  • TodoObject.h — класс для типа Todo
  • QueryObject.h — базовый класс для резолверов Query
  • MutationObject.h — базовый класс для резолверов Mutation
  • schema.h — интеграция схемы

Эти файлы содержат сгенерированные интерфейсы, которые мы должны реализовать.

Шаг 3: Реализация резолверов

Создадим файл resolver.h с объявлениями:

#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;
};

Теперь реализуем логику в resolver.cpp:

#include "resolver.h"
#include "generated/TodoObject.h"
#include <algorithm>

std::vector<Todo> QueryResolver::todos_ = {
    {"1", "Изучить GraphQL", false},
    {"2", "Написать туториал", true}
};

// Резолвер для списка задач
std::vector<std::shared_ptr<graphql::todo::TodoObject>> 
QueryResolver::getTodos() const {
    std::vector<std::shared_ptr<graphql::todo::TodoObject>> result;
    for (const auto& todo : todos_) {
        auto obj = std::make_shared<graphql::todo::TodoObject>();
        obj->setId(todo.id);
        obj->setTitle(todo.title);
        obj->setCompleted(todo.completed);
        result.push_back(obj);
    }
    return result;
}

// Резолвер для одной задачи
std::shared_ptr<graphql::todo::TodoObject> 
QueryResolver::getTodo(const std::string& id) const {
    auto it = std::find_if(todos_.begin(), todos_.end(),
        [&id](const Todo& t) { return t.id == id; });
    if (it == todos_.end()) return nullptr;
    
    auto obj = std::make_shared<graphql::todo::TodoObject>();
    obj->setId(it->id);
    obj->setTitle(it->title);
    obj->setCompleted(it->completed);
    return obj;
}

// Мутация: добавление задачи
std::shared_ptr<graphql::todo::TodoObject> 
MutationResolver::applyAddTodo(const std::string& title) {
    static int nextId = 3;
    Todo newTodo{std::to_string(nextId++), title, false};
    todos_.push_back(newTodo);
    
    auto obj = std::make_shared<graphql::todo::TodoObject>();
    obj->setId(newTodo.id);
    obj->setTitle(newTodo.title);
    obj->setCompleted(newTodo.completed);
    return obj;
}

// Мутация: завершение задачи
std::shared_ptr<graphql::todo::TodoObject> 
MutationResolver::applyCompleteTodo(const std::string& id) {
    auto it = std::find_if(todos_.begin(), todos_.end(),
        [&id](Todo& t) { return t.id == id; });
    if (it == todos_.end()) return nullptr;
    
    it->completed = true                

Блоги

Рекомендаций по книгам