GraphQL API с C++: пошаговый туториал
GraphQL — это язык запросов для API, разработанный Facebook. В отличие от REST, он позволяет клиенту запрашивать только те данные, которые ему нужны, что снижает объем передаваемой информации и ускоряет работу приложений. В этом туториале мы создадим простой GraphQL сервер на C++ с использованием библиотеки graphql-cpp. Вы узнаете, как определить схему, написать резолверы и обрабатывать запросы и мутации.
Что такое GraphQL и почему C++?
GraphQL предоставляет единую конечную точку для всех запросов. Основные концепции:
- Схема (Schema) — описание доступных типов данных и операций (запросы, мутации, подписки).
- Запросы (Queries) — операции чтения данных.
- Мутации (Mutations) — операции записи/изменения данных.
- Резолверы (Resolvers) — функции, возвращающие данные для каждого поля.
C++ — мощный язык для высоконагруженных систем. Использование GraphQL с C++ позволяет создавать эффективные и масштабируемые API. Библиотека graphql-cpp предоставляет удобный интерфейс для интеграции.
Установка и настройка проекта
Для работы нам понадобятся:
- Компилятор C++17 (например, g++ или MSVC).
- Библиотека
graphql-cpp(установка через vcpkg или сборка из исходников). - HTTP-сервер (мы будем использовать
cpp-httplibдля простоты).
Установка через vcpkg
vcpkg install graphql-cpp
vcpkg install cpp-httplib
Структура проекта
Создайте файлы:
main.cpp— точка входа и HTTP-сервер.schema.hpp— определение схемы GraphQL.resolvers.hpp— реализация резолверов.CMakeLists.txt— конфигурация сборки.
Определение схемы GraphQL
Создадим простую схему для управления списком пользователей. Тип User содержит поля id, name и email. Запросы: users (список всех пользователей) и user(id: ID!) (один пользователь). Мутация: addUser(name: String!, email: String!): User.
В файле schema.hpp:
#ifndef SCHEMA_HPP
#define SCHEMA_HPP
#include <graphqlcpp/GraphQLSchema.h>
using namespace graphqlcpp;
// Определяем тип User
auto userType = std::make_shared<ObjectType>(
"User",
{
{"id", Type::NonNull(Type::ID)},
{"name", Type::NonNull(Type::String)},
{"email", Type::NonNull(Type::String)}
}
);
// Определяем Query
auto queryType = std::make_shared<ObjectType>(
"Query",
{
{"users", Type::List(Type::NonNull(userType))},
{"user", Type::NonNull(userType), {{"id", Type::NonNull(Type::ID)}}}
}
);
// Определяем Mutation
auto mutationType = std::make_shared<ObjectType>(
"Mutation",
{
{"addUser", Type::NonNull(userType), {
{"name", Type::NonNull(Type::String)},
{"email", Type::NonNull(Type::String)}
}}
}
);
// Собираем схему
auto schema = std::make_shared<Schema>(queryType, mutationType);
#endif // SCHEMA_HPP
Реализация резолверов
Резолверы — это функции, которые возвращают данные для каждого поля. В нашем примере данные будут храниться в глобальном векторе. В файле resolvers.hpp:
#ifndef RESOLVERS_HPP
#define RESOLVERS_HPP
#include <vector>
#include <string>
#include <graphqlcpp/Resolvers.h>
using namespace graphqlcpp;
struct User {
std::string id;
std::string name;
std::string email;
};
std::vector<User> users = {
{"1", "Alice", "alice@example.com"},
{"2", "Bob", "bob@example.com"}
};
// Резолвер для списка пользователей
ResolveResult resolveUsers(const ResolveArgs& args) {
return ResolveResult::list(users);
}
// Резолвер для одного пользователя
ResolveResult resolveUser(const ResolveArgs& args) {
auto id = args.at("id").asString();
for (const auto& user : users) {
if (user.id == id) {
return ResolveResult::object(user);
}
}
return ResolveResult::null();
}
// Резолвер для мутации addUser
ResolveResult resolveAddUser(const ResolveArgs& args) {
auto name = args.at("name").asString();
auto email = args.at("email").asString();
std::string newId = std::to_string(users.size() + 1);
users.push_back({newId, name, email});
return ResolveResult::object(users.back());
}
// Привязываем резолверы к полям схемы
void bindResolvers() {
schema->getQueryType()->setResolver("users", resolveUsers);
schema->getQueryType()->setResolver("user", resolveUser);
schema->getMutationType()->setResolver("addUser", resolveAddUser);
}
#endif // RESOLVERS_HPP
Создание HTTP-сервера и обработка запросов
Теперь объединим всё в main.cpp. Используем cpp-httplib для создания простого HTTP-сервера, который принимает POST-запросы на /graphql и возвращает JSON-ответ.
#include <iostream>
#include <httplib.h>
#include <nlohmann/json.hpp>
#include "schema.hpp"
#include "resolvers.hpp"
using json = nlohmann::json;
int main() {
bindResolvers();
httplib::Server svr;
svr.Post("/graphql", [](const httplib::Request& req, httplib::Response& res) {
auto body = json::parse(req.body);
std::string query = body["query"];
// Выполняем запрос
auto result = schema->execute(query);
res.set_content(result.dump(), "application/json");
});
std::cout << "Сервер запущен на http://