GraphQL API на C++: полное руководство с примерами

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

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

Начать курс

GraphQL API с C++: пошаговый туториал

GraphQL — это мощный язык запросов для API, который позволяет клиентам получать именно те данные, которые им нужны, и ничего лишнего. Хотя C++ не является самым популярным языком для создания веб-API, его производительность и контроль над памятью делают его отличным выбором для высоконагруженных систем. В этом туториале мы создадим работающий GraphQL сервер на C++ с использованием библиотеки graphql-cpp.

Что потребуется для старта

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

  • Компилятор с поддержкой C++17 (GCC 8+, Clang 7+, MSVC 2019+)
  • CMake версии 3.14 или выше
  • Библиотека graphql-cpp (установка через vcpkg или сборка из исходников)
  • Библиотека libmicrohttpd для HTTP-сервера

Установим зависимости через vcpkg:

git clone https://github.com/microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg install graphql-cpp libmicrohttpd

Создание базовой структуры проекта

Начнём с настройки CMake проекта. Создайте файл CMakeLists.txt:

cmake_minimum_required(VERSION 3.14)
project(graphql-cpp-tutorial)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(graphql-cpp CONFIG REQUIRED)
find_package(MHD CONFIG REQUIRED)

add_executable(graphql-server main.cpp)
target_link_libraries(graphql-server 
    graphql-cpp::graphql-cpp
    MHD::MHD
)

Теперь создадим основной файл main.cpp с минимальным сервером:

#include <graphql-cpp/GraphQL.h>
#include <microhttpd.h>
#include <iostream>
#include <string>

using namespace graphql::cpp;

// Функция обработки HTTP запросов
static enum MHD_Result request_handler(void* cls,
    struct MHD_Connection* connection,
    const char* url,
    const char* method,
    const char* version,
    const char* upload_data,
    size_t* upload_data_size,
    void** con_cls) {
    
    const char* response_str = "{\"data\":{\"hello\":\"world\"}}";
    struct MHD_Response* response = MHD_create_response_from_buffer(
        strlen(response_str), 
        (void*)response_str, 
        MHD_RESPMEM_PERSISTENT
    );
    MHD_add_response_header(response, "Content-Type", "application/json");
    int ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
    MHD_destroy_response(response);
    return ret == MHD_YES ? MHD_YES : MHD_NO;
}

int main() {
    struct MHD_Daemon* daemon = MHD_start_daemon(
        MHD_USE_INTERNAL_POLLING_THREAD,
        4000,
        NULL, NULL,
        &request_handler,
        NULL,
        MHD_OPTION_END
    );
    
    if (daemon == NULL) {
        std::cerr << "Failed to start server" << std::endl;
        return 1;
    }
    
    std::cout << "Server running on http://localhost:4000/graphql" << std::endl;
    getchar();
    MHD_stop_daemon(daemon);
    return 0;
}

Определение GraphQL схемы

Теперь добавим настоящую GraphQL схему. Создадим тип Book и корневой тип Query:

#include <graphql-cpp/Schema.h>
#include <graphql-cpp/Type.h>
#include <vector>
#include <memory>

using namespace graphql::cpp;

// Модель данных
struct Book {
    int id;
    std::string title;
    std::string author;
    int year;
};

// Репозиторий книг (имитация базы данных)
class BookRepository {
public:
    static std::vector<Book> getAll() {
        return {
            {1, "Война и мир", "Лев Толстой", 1869},
            {2, "Преступление и наказание", "Фёдор Достоевский", 1866},
            {3, "Мастер и Маргарита", "Михаил Булгаков", 1967}
        };
    }
    
    static Book getById(int id) {
        auto books = getAll();
        for (const auto& book : books) {
            if (book.id == id) return book;
        }
        throw std::runtime_error("Book not found");
    }
};

// Создание GraphQL схемы
std::shared_ptr<Schema> createSchema() {
    auto schema = std::make_shared<Schema>();
    
    // Тип Book
    auto bookType = std::make_shared<ObjectType>("Book");
    bookType->addField("id", Type::NonNullInt());
    bookType->addField("title", Type::NonNullString());
    bookType->addField("author", Type::NonNullString());
    bookType->addField("year", Type::Int());
    
    // Корневой тип Query
    auto queryType = std::make_shared<ObjectType>("Query");
    
    // Поле books: возвращает список всех книг
    queryType->addField("books", Type::List(bookType), 
        [](const ResolverArgs& args) -> json {
            auto books = BookRepository::getAll();
            json result = json::array();
            for (const auto& book : books) {
                result.push_back({
                    {"id", book.id},
                    {"title", book.title},
                    {"author", book.author},
                    {"year", book.year}
                });
            }
            return result;
        }
    );
    
    // Поле book: возвращает книгу по ID
    queryType->addField("book", bookType, 
        [](const ResolverArgs& args) -> json {
            int id = args.getArgument<int>("id");
            auto book = BookRepository::getById(id);
            return {
                {"id", book.id},
                {"title", book.title},
                {"author", book.author},
                {"year", book.year}
            };
        },
        Argument("id", Type::NonNullInt())
    );
    
    schema->setQueryType(queryType);
    return schema;
}

Добавление мутаций (изменение данных)

Добавим возможность добавлять новые книги через мутации:

// Мутация для добавления книги
queryType->addField("addBook", bookType,
    [](const ResolverArgs& args) -> json {
        static int nextId = 4;
        Book newBook;
        newBook.id = nextId++;
        newBook.title = args.getArgument<std::string>("title");
        newBook.author = args.getArgument<std::string>("author");
        newBook.year = args.getArgument<int>("year");
        
        // В реальном приложении здесь было бы сохран                

Блоги

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