Введение: Зачем писать REST API на C++?
C++ традиционно ассоциируется с системным программированием, играми и высоконагруженными приложениями. Однако, современный C++ (начиная со стандартов C++11/17/20) предоставляет все необходимые инструменты для быстрой разработки веб-сервисов. Написание REST API на C++ может быть оправдано, когда требуется максимальная производительность, низкое потребление памяти или интеграция с существующим C++ кодом (например, библиотеками компьютерного зрения или численных расчетов).
В этом руководстве мы создадим полноценный REST API на C++ за 30 минут. Для этого мы используем легковесную и элегантную библиотеку Crow. Она не требует сложной настройки, поддерживает маршрутизацию, JSON (через json.hpp) и middleware. К концу статьи у вас будет работающий сервер с тремя эндпоинтами.
Шаг 1: Настройка окружения и установка Crow
Для работы нам понадобится компилятор с поддержкой C++17 (g++ 7+, clang 5+ или MSVC 2017+) и система сборки CMake. Crow — это "header-only" библиотека, что упрощает установку: достаточно скачать один заголовочный файл.
Установка
- Скачайте последнюю версию Crow с GitHub (или используйте
git clone). - Скопируйте папку
includeв ваш проект. - Установите
nlohmann/json(также header-only) для работы с JSON.
Структура проекта
my_rest_api/
├── CMakeLists.txt
├── main.cpp
└── include/
├── crow.h
└── json.hpp
CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(my_rest_api)
set(CMAKE_CXX_STANDARD 17)
include_directories(include)
add_executable(my_rest_api main.cpp)
target_link_libraries(my_rest_api pthread)
Сборка: mkdir build && cd build && cmake .. && make
Шаг 2: Создание базового сервера и маршрутов
Crow использует простой DSL для определения маршрутов. Давайте создадим сервер, который слушает порт 8080 и обрабатывает GET и POST запросы.
Базовый код сервера
#include "crow.h"
#include <string>
int main() {
crow::SimpleApp app;
// Простой GET маршрут
CROW_ROUTE(app, "/")([](){
return "Добро пожаловать в REST API на C++!";
});
// GET с параметром пути
CROW_ROUTE(app, "/user/<int>")([](int user_id){
return crow::response("ID пользователя: " + std::to_string(user_id));
});
app.port(8080).multithreaded().run();
}
Этот код создает два эндпоинта. crow::SimpleApp — основной класс приложения. Метод multithreaded() включает обработку запросов в пуле потоков. Запустите сервер и проверьте в браузере http://localhost:8080/.
Типы параметров в маршрутах
Crow поддерживает следующие типы параметров в пути:
<int>— целое число<string>— строка<path>— остаток пути (например,/files/<path>)<float>— число с плавающей точкой
Шаг 3: Работа с JSON и POST запросами
Настоящий REST API должен уметь принимать и возвращать JSON. Подключим nlohmann/json и реализуем CRUD-подобные операции.
Пример: Простая "База данных" в памяти
#include "crow.h"
#include "json.hpp"
#include <unordered_map>
#include <memory>
using json = nlohmann::json;
struct Task {
int id;
std::string title;
bool completed;
};
std::unordered_map<int, std::shared_ptr<Task>> tasks;
int next_id = 1;
int main() {
crow::SimpleApp app;
// GET /tasks — получить все задачи
CROW_ROUTE(app, "/tasks")([](){
json j = json::array();
for (const auto& [id, task] : tasks) {
j.push_back({{"id", task->id}, {"title", task->title}, {"completed", task->completed}});
}
return crow::response(j.dump());
});
// POST /tasks — создать новую задачу
CROW_ROUTE(app, "/tasks").methods("POST"_method)([](const crow::request& req){
auto body = json::parse(req.body);
auto task = std::make_shared<Task>();
task->id = next_id++;
task->title = body["title"].get<std::string>();
task->completed = body.value("completed", false);
tasks[task->id] = task;
json response = {{"id", task->id}, {"title", task->title}, {"completed", task->completed}};
return crow::response(201, response.dump());
});
// GET /tasks/<int> — получить задачу по ID
CROW_ROUTE(app, "/tasks/<int>")([](int id){
if (tasks.count(id) == 0) {
return crow::response(404, "Задача не найдена");
}
auto task = tasks[id];
json j = {{"id", task->id}, {"title", task->title}, {"completed", task->completed}};
return crow::response(j.dump());
});
app.port(8080).multithreaded().run();
}
Здесь мы используем std::unordered_map для хранения задач. Обратите внимание на обработку POST: мы читаем тело запроса (req.body), парсим JSON и возвращаем ответ с кодом 201 (Created).
Тестирование через curl
# Создать задачу
curl -X POST http://localhost:8080/tasks -H "Content-Type: application/json" -d '{"title":"Изучить C++","completed":false}'
# Получить все задачи
curl http://localhost:8080/tasks
# Получить задачу по ID
curl http://localhost:8080/tasks/1
Шаг 4: Обработка ошибок и CORS (дополнительно)