Введение: зачем писать REST API на C++?
REST API (Representational State Transfer) — это архитектурный стиль взаимодействия компонентов распределённого приложения в сети. Обычно для написания REST API выбирают Python (Flask, FastAPI), JavaScript (Express.js) или Java. Однако C++ остаётся незаслуженно обойдённым вниманием. А зря.
Современные библиотеки, такие как Crow, cpp-httplib и Drogon, позволяют создавать высокопроизводительные REST API на C++ буквально за полчаса. Благодаря скорости работы C++ и минимальному потреблению памяти, такие API идеально подходят для:
- микросервисов с высокими требованиями к производительности;
- встраиваемых систем и IoT-устройств;
- обработки большого числа параллельных запросов;
- реализации шлюзов и прокси-серверов.
В этой статье мы на практике создадим простое REST API на C++ с использованием библиотеки Crow. Вы увидите, что это не сложнее, чем на Python, а по скорости работы — в разы быстрее.
Настройка окружения и установка библиотеки Crow
Для нашего проекта мы будем использовать Crow — минималистичный и очень быстрый C++ микро-веб-фреймворк. Он поддерживает маршрутизацию, middleware, JSON-сериализацию и работает на Windows, Linux и macOS.
Что потребуется
- Компилятор C++17 или новее (GCC 8+, Clang 7+, MSVC 2019+);
- CMake версии 3.14+;
- Библиотека
asio(устанавливается автоматически с Crow); - Библиотека
nlohmann/json(для работы с JSON).
Установка Crow
Crow — header-only библиотека. Это значит, что вам не нужно её компилировать — достаточно скопировать заголовочные файлы в проект. Самый простой способ — через CMake FetchContent.
Создайте структуру проекта:
rest-api-cpp/
├── CMakeLists.txt
├── src/
│ └── main.cpp
└── include/
Содержимое файла CMakeLists.txt:
cmake_minimum_required(VERSION 3.14)
project(rest_api_cpp)
set(CMAKE_CXX_STANDARD 17)
# Подключаем Crow
include(FetchContent)
FetchContent_Declare(
crow
GIT_REPOSITORY https://github.com/ipkn/crow.git
GIT_TAG master
)
FetchContent_MakeAvailable(crow)
# Подключаем nlohmann/json
FetchContent_Declare(
json
GIT_REPOSITORY https://github.com/nlohmann/json.git
GIT_TAG v3.11.2
)
FetchContent_MakeAvailable(json)
add_executable(rest_api src/main.cpp)
target_link_libraries(rest_api PRIVATE Crow::Crow nlohmann_json::nlohmann_json)
После этого выполните:
mkdir build && cd build
cmake ..
make
Всё готово к написанию кода.
Создание базового REST API на C++ с помощью Crow
Напишем простое API для управления списком задач (Task Manager). Оно будет поддерживать четыре основных HTTP-метода: GET, POST, PUT, DELETE.
Каркас сервера и GET-эндпоинт
#include <crow.h>
#include <nlohmann/json.hpp>
#include <vector>
#include <string>
using json = nlohmann::json;
struct Task {
int id;
std::string title;
bool completed;
};
std::vector<Task> tasks = {
{1, "Изучить Crow", false},
{2, "Написать REST API", false}
};
int next_id = 3;
int main() {
crow::SimpleApp app;
// GET /tasks — получить все задачи
CROW_ROUTE(app, "/tasks")
.methods("GET"_method)
([](){
json j = json::array();
for (const auto& t : tasks) {
j.push_back({{"id", t.id}, {"title", t.title}, {"completed", t.completed}});
}
return crow::response(j.dump());
});
app.port(8080).multithreaded().run();
}
Этот код запускает HTTP-сервер на порту 8080. При GET-запросе к /tasks возвращается JSON-массив со всеми задачами.
POST — добавление новой задачи
// POST /tasks — создать новую задачу
CROW_ROUTE(app, "/tasks")
.methods("POST"_method)
([](const crow::request& req){
auto body = json::parse(req.body);
Task new_task;
new_task.id = next_id++;
new_task.title = body["title"];
new_task.completed = false;
tasks.push_back(new_task);
json resp = {{"id", new_task.id}, {"title", new_task.title}, {"completed", new_task.completed}};
return crow::response(201, resp.dump());
});
Обратите внимание: мы возвращаем HTTP-статус 201 (Created) и JSON с данными созданной задачи.
PUT — обновление задачи по ID
// PUT /tasks/<int> — обновить задачу
CROW_ROUTE(app, "/tasks/<int>")
.methods("PUT"_method)
([](const crow::request& req, int id){
auto it = std::find_if(tasks.begin(), tasks.end(), [id](const Task& t){ return t.id == id; });
if (it == tasks.end()) {
return crow::response(404, "Task not found");
}
auto body = json::parse(req.body);
if (body.contains("title")) it->title = body["title"];
if (body.contains("completed")) it->completed = body["completed"];
json resp = {{"id", it->id}, {"title", it->title}, {"completed", it->completed}};
return crow::response(resp.dump());
});
DELETE — удаление задачи
// DELETE /tasks/<int> — удалить задачу
CROW_ROUTE(app, "/tasks/<int>")
.methods("DELETE"_method)
([](int id){
auto it = std::remove_if(tasks.begin(), tasks.end(), [id](const Task& t){ return t.id == id; });
if (it == tasks.end()) {
return crow::response(404, "Task not found");
}
tasks.erase(it, tasks.end());
return crow::response(204);
});
Метод DELETE возвращает статус 204 (No Content) — это стандарт для успешного удаления.