GraphQL API с C++: пошаговый туториал для начинающих
GraphQL — это современный язык запросов для API, который позволяет клиентам запрашивать только те данные, которые им действительно нужны. В отличие от REST, где структура ответа фиксирована, GraphQL даёт гибкость и контроль. В этом туториале мы разберём, как создать простой GraphQL API на C++ с нуля. Вы узнаете, как подключить библиотеку graphql-cpp, определить схему, написать резолверы и протестировать запросы. Статья рассчитана на начинающих, знакомых с основами C++.
Почему C++? Этот язык обеспечивает высокую производительность, что критично для API с высокой нагрузкой. GraphQL на C++ часто используется в системах реального времени, игровых движках и высоконагруженных веб-сервисах. Начнём!
Установка и настройка окружения
Для работы нам понадобится компилятор с поддержкой C++17 (например, GCC 8+ или Clang 10+), CMake и библиотека graphql-cpp. Установим всё необходимое.
Шаг 1: Установка зависимостей
В Ubuntu/Debian выполните:
sudo apt update
sudo apt install build-essential cmake libboost-all-dev libssl-dev
Для macOS используйте Homebrew:
brew install cmake boost openssl
Шаг 2: Клонирование библиотеки graphql-cpp
Библиотека graphql-cpp — это легковесная реализация GraphQL на C++. Клонируем репозиторий:
git clone https://github.com/your-repo/graphql-cpp.git
cd graphql-cpp
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j4
sudo make install
После установки создадим новый проект. Структура папок:
my_graphql_api/
├── CMakeLists.txt
├── src/
│ ├── main.cpp
│ └── schema.cpp
└── include/
└── schema.h
Шаг 3: Настройка CMakeLists.txt
Создайте файл CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
project(GraphQLExample)
set(CMAKE_CXX_STANDARD 17)
find_package(graphql-cpp REQUIRED)
find_package(Boost REQUIRED COMPONENTS system)
add_executable(graphql_example src/main.cpp src/schema.cpp)
target_include_directories(graphql_example PRIVATE include)
target_link_libraries(graphql_example graphql-cpp::graphql-cpp Boost::system)
Определение схемы GraphQL
Схема — это ядро GraphQL API. Она описывает типы данных, запросы (queries) и мутации (mutations). В нашем примере создадим API для управления списком книг.
Создание типа Book
В файле include/schema.h объявим структуру данных и функцию для создания схемы:
#ifndef SCHEMA_H
#define SCHEMA_H
#include <graphql-cpp/graphql.hpp>
#include <string>
#include <vector>
struct Book {
int id;
std::string title;
std::string author;
int year;
};
graphql::Schema createBookSchema();
#endif // SCHEMA_H
Реализация схемы
В файле src/schema.cpp определим типы и корневой запрос:
#include "schema.h"
#include <graphql-cpp/graphql.hpp>
#include <vector>
#include <memory>
using namespace graphql;
// Временное хранилище книг
std::vector<Book> books = {
{1, "C++ Primer", "Stanley B. Lippman", 2012},
{2, "Effective Modern C++", "Scott Meyers", 2014}
};
Schema createBookSchema() {
// 1. Определяем тип Book
ObjectType bookType("Book");
bookType.addField("id", Type::NonNull(Type::Int()));
bookType.addField("title", Type::NonNull(Type::String()));
bookType.addField("author", Type::NonNull(Type::String()));
bookType.addField("year", Type::Int());
// 2. Определяем корневой запрос
ObjectType queryType("Query");
queryType.addField("books", Type::List(Type::NonNull(bookType)),
[](const auto& args) -> json {
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;
}
);
queryType.addField("book", bookType,
[](const auto& args) -> json {
int id = args.at("id").get<int>();
for (const auto& book : books) {
if (book.id == id) {
return {
{"id", book.id},
{"title", book.title},
{"author", book.author},
{"year", book.year}
};
}
}
return nullptr; // null, если книга не найдена
},
// Аргументы поля
{{"id", Type::NonNull(Type::Int())}}
);
// 3. Собираем схему
Schema schema;
schema.addType(bookType);
schema.setQueryType(queryType);
return schema;
}
Написание резолверов и запуск сервера
Резолверы — это функции, которые возвращают данные для каждого поля. В нашем примере они уже встроены в объявление полей. Теперь создадим HTTP-сервер, который будет принимать GraphQL-запросы.
Создание HTTP-сервера с Boost.Beast
В файле src/main.cpp напишем простой сервер на Boost.Beast:
#include "schema.h"
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <boost/asio.hpp>
#include <iostream>
#include <string>
using namespace boost::beast;
using namespace boost::asio;
using tcp = boost::asio::ip::tcp;
void handleRequest(http::request<http::string_body>& req, http::response<http::string_body>& res) {
if (req.method() != http::verb::post) {
res.result(http::status::method_not_allowed);
res.body() = "Only POST requests allowed";
return;
}
// Парсим GraphQL-запрос
auto schema = createBookSchema();
auto body = req.body();
auto requestJson = nlohmann::json::parse(body);
auto query = requestJson["query"].get<std::string>();
// Выполняем запрос
auto result = schema.execute(query);