Введение: Почему C++ для REST API — это не страшно
Многие начинающие разработчики считают, что C++ — это слишком сложно для создания веб-сервисов. Однако современный C++ (начиная со стандарта C++11) предоставляет мощные и элегантные инструменты для разработки высокопроизводительных REST API. В этом руководстве мы за 30 минут создадим полноценный REST API на C++ с использованием легковесной библиотеки Crow.
Мы разберемся, как настроить сервер, обрабатывать GET и POST запросы, работать с JSON и возвращать данные. К концу статьи у вас будет работающий прототип, который можно использовать как основу для своих проектов.
Что такое REST API?
REST (Representational State Transfer) — это архитектурный стиль для создания веб-сервисов. REST API использует HTTP методы (GET, POST, PUT, DELETE) для управления ресурсами. Данные обычно передаются в формате JSON.
1. Подготовка окружения: установка библиотек
Для быстрого старта мы будем использовать библиотеку Crow — минималистичный C++ веб-фреймворк, который не требует сложной настройки. Нам также понадобится библиотека для работы с JSON — nlohmann/json.
Установка зависимостей (Linux/macOS)
# Устанавливаем необходимые пакеты
sudo apt-get install libboost-all-dev cmake g++
# Скачиваем Crow (single-header версию)
wget https://raw.githubusercontent.com/CrowCpp/Crow/master/include/crow.h
# Скачиваем библиотеку JSON
wget https://github.com/nlohmann/json/releases/download/v3.11.2/json.hpp
Установка зависимостей (Windows с MinGW)
Для Windows используйте vcpkg:
vcpkg install crow
vcpkg install nlohmann-json
2. Создаем простой HTTP сервер на C++
Начнем с базового сервера, который будет отвечать на запросы. Создайте файл main.cpp:
#include "crow.h"
int main() {
crow::SimpleApp app;
// Простой маршрут GET
CROW_ROUTE(app, "/")([](){
return "Привет, мир! REST API на C++ работает!";
});
// Запускаем сервер на порту 8080
app.port(8080).multithreaded().run();
}
Скомпилируйте и запустите:
g++ -std=c++17 -pthread main.cpp -o api_server
./api_server
Откройте браузер и перейдите на http://localhost:8080. Вы увидите приветственное сообщение.
3. Добавляем обработку JSON и CRUD операции
Теперь добавим поддержку JSON и реализуем простую базу данных в памяти для хранения пользователей.
Включаем поддержку JSON
#include "crow.h"
#include "json.hpp"
#include <vector>
#include <string>
using json = nlohmann::json;
struct User {
int id;
std::string name;
std::string email;
};
std::vector<User> users;
int next_id = 1;
Маршрут GET для получения списка пользователей
CROW_ROUTE(app, "/users")([](){
json response = json::array();
for (const auto& user : users) {
response.push_back({
{"id", user.id},
{"name", user.name},
{"email", user.email}
});
}
return crow::response(response.dump());
});
Маршрут POST для создания нового пользователя
CROW_ROUTE(app, "/users")
.methods("POST"_method)([](const crow::request& req){
auto body = json::parse(req.body);
User new_user;
new_user.id = next_id++;
new_user.name = body["name"];
new_user.email = body["email"];
users.push_back(new_user);
json response = {
{"id", new_user.id},
{"name", new_user.name},
{"email", new_user.email}
};
return crow::response(201, response.dump());
});
Маршрут DELETE для удаления пользователя
CROW_ROUTE(app, "/users/<int>")
.methods("DELETE"_method)([](int user_id){
auto it = std::remove_if(users.begin(), users.end(),
[user_id](const User& u) { return u.id == user_id; });
if (it != users.end()) {
users.erase(it, users.end());
return crow::response(200, "Пользователь удален");
} else {
return crow::response(404, "Пользователь не найден");
}
});
4. Полный код и тестирование API
Вот полный код нашего REST API на C++:
#include "crow.h"
#include "json.hpp"
#include <vector>
#include <string>
#include <algorithm>
using json = nlohmann::json;
struct User {
int id;
std::string name;
std::string email;
};
std::vector<User> users;
int next_id = 1;
int main() {
crow::SimpleApp app;
// Корневой маршрут
CROW_ROUTE(app, "/")([](){
return "REST API на C++ работает!";
});
// GET: получить всех пользователей
CROW_ROUTE(app, "/users")([](){
json response = json::array();
for (const auto& user : users) {
response.push_back({
{"id", user.id},
{"name", user.name},
{"email", user.email}
});
}
return crow::response(response.dump());
});
// POST: создать пользователя
CROW_ROUTE(app, "/users")
.methods("POST"_method)([](const crow::request& req){
try {
auto body = json::parse(req.body);
if (!body.contains("name") || !body.contains("email")) {
return crow::response(400, "Необходимы поля name и email");
}
User new_user;
new_user.id = next_id++;
new_user.name = body["name"];
new_user.email = body["email"];
users.push_back(new_user);
json response = {
{"id", new_user.id},
{"name", new_user.name},
{"email", new_user.email}
};
return crow::response(201, response.dump());
} catch (const std::exception& e) {
return crow::response(400, "Ошибка парсинга JSON");
}
});
// DELETE: удалить пользователя по ID
CROW_ROUTE(app, "/users/<int>")
.methods("DELETE"_method)([](int user_id){
auto it = std::remove_if(users.begin(), users.end(),
[user_id](const User& u) { return u.id == user_id; });
if (it != users.end()) {
users.erase(it, users.end());
return crow::response(200,