GraphQL библиотека C++: cppgraphqlgen
cppgraphqlgen — это современная библиотека на C++ для реализации серверной части GraphQL. Она позволяет разработчикам создавать типобезопасные, быстрые и масштабируемые API, используя преимущества статической типизации C++. Библиотека генерирует код на основе схемы GraphQL (.graphql файлов), что минимизирует ручное написание резолверов и снижает вероятность ошибок.
Основные возможности
- Генерация кода из схемы — на вход подаётся файл schema.graphql, на выходе получаются C++ классы и функции.
- Типобезопасность — все типы GraphQL (String, Int, Float, Boolean, ID, Enum, Input, Object) компилируются в соответствующие типы C++.
- Поддержка подписок (Subscriptions) — реализована через WebSocket и асинхронные потоки.
- Валидация запросов — встроенная проверка синтаксиса и семантики GraphQL-запросов.
- Интеграция с HTTP — работает поверх любого C++ HTTP-сервера (например,
beastиз Boost). - Поддержка директив — кастомные директивы для расширения функционала.
Установка
Для установки cppgraphqlgen требуется компилятор с поддержкой C++17 и система сборки CMake. Установка через vcpkg или сборка из исходников:
# Через vcpkg
vcpkg install cppgraphqlgen
# Сборка из репозитория
git clone https://github.com/microsoft/cppgraphqlgen.git
cd cppgraphqlgen
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
cmake --build . --target install
Пример использования
Рассмотрим простой пример: создадим схему GraphQL для получения информации о пользователе и книге. Сначала определим схему schema.graphql:
type Query {
user(id: ID!): User
book(id: ID!): Book
}
type User {
id: ID!
name: String!
email: String
}
type Book {
id: ID!
title: String!
author: String!
}
После генерации кода (команда graphqlgen) получаем файл Generated.h. Теперь напишем резолверы на C++:
#include "Generated.h"
#include <unordered_map>
// Пример данных (в реальном проекте — БД)
std::unordered_map<std::string, User> users = {
{"1", {"1", "Alice", "alice@example.com"}},
{"2", {"2", "Bob", nullptr}}
};
std::unordered_map<std::string, Book> books = {
{"10", {"10", "C++ Primer", "Lippman"}},
{"20", {"20", "Effective Modern C++", "Meyers"}}
};
// Резолвер для Query.user
User resolveGetUser(const std::string& id) {
auto it = users.find(id);
if (it != users.end()) {
return it->second;
}
throw std::runtime_error("User not found");
}
// Резолвер для Query.book
Book resolveGetBook(const std::string& id) {
auto it = books.find(id);
if (it != books.end()) {
return it->second;
}
throw std::runtime_error("Book not found");
}
Теперь настраиваем сервер и запускаем обработку запросов:
#include <graphqlservice/GraphQLService.h>
#include <beast/http.hpp>
int main() {
// Создаём сервис со схемой
auto service = std::make_shared<graphql::service::GraphQLService>();
// Регистрируем резолверы
service->addResolver("Query", "user", resolveGetUser);
service->addResolver("Query", "book", resolveGetBook);
// Запускаем HTTP-сервер (упрощённо)
http::server server("0.0.0.0", 8080, service);
server.run();
return 0;
}
Обработка ошибок и валидация
Библиотека автоматически проверяет корректность входящих запросов. Если резолвер выбрасывает исключение, cppgraphqlgen преобразует его в GraphQL-ошибку с соответствующим кодом. Пример обработки:
// Кастомное исключение
class NotFoundException : public std::exception {
const char* what() const noexcept override {
return "Resource not found";
}
};
// Резолвер с обработкой
User resolveGetUserSafe(const std::string& id) {
auto it = users.find(id);
if (it == users.end()) {
throw NotFoundException();
}
return it->second;
}
Преимущества и недостатки
Плюсы:
- Полная типобезопасность на