Введение: почему C++ для REST API — это не шутка
C++ традиционно ассоциируется с системным программированием, играми и высоконагруженными вычислениями. Однако в последние годы этот язык всё чаще используется для создания веб-сервисов и REST API. Почему? Потому что C++ даёт невероятную производительность и контроль над памятью, что критично для высоконагруженных backend-решений.
В этом руководстве мы за 30 минут создадим полноценный REST API на C++ с использованием библиотеки cpp-httplib (одна заголовочная библиотека, не требует установки). Вы научитесь:
- Настраивать HTTP-сервер на C++
- Обрабатывать GET, POST, PUT и DELETE запросы
- Работать с JSON через
nlohmann/json - Собирать и запускать проект
Этот материал подойдёт как новичкам, так и опытным разработчикам, которые хотят попробовать C++ в веб-разработке.
Шаг 1: Подготовка окружения и установка зависимостей
Для работы нам понадобятся:
- Компилятор C++ (g++ или clang) с поддержкой C++17
- Библиотека
cpp-httplib(одна h-файл) - Библиотека
nlohmann/json(одна hpp-файл)
Скачайте обе библиотеки:
# Установка cpp-httplib
wget https://raw.githubusercontent.com/yhirose/cpp-httplib/master/httplib.h
# Установка nlohmann/json
wget https://raw.githubusercontent.com/nlohmann/json/develop/single_include/nlohmann/json.hpp
Структура проекта будет простой:
my_rest_api/
├── main.cpp
├── httplib.h
└── json.hpp
Шаг 2: Создание базового HTTP-сервера
Начнём с минимального сервера, который будет слушать порт 8080 и отвечать на GET-запросы.
Создайте файл main.cpp:
#include "httplib.h"
#include "json.hpp"
#include <iostream>
using namespace httplib;
using json = nlohmann::json;
int main() {
Server svr;
// GET-запрос к корню
svr.Get("/", [](const Request& req, Response& res) {
res.set_content("Hello, REST API on C++!", "text/plain");
});
std::cout << "Server started on http://localhost:8080" << std::endl;
svr.listen("0.0.0.0", 8080);
return 0;
}
Скомпилируйте и запустите:
g++ -std=c++17 -pthread -o server main.cpp
./server
Откройте браузер или используйте curl http://localhost:8080 — вы увидите приветственное сообщение. Сервер работает!
Шаг 3: Реализация CRUD-операций с JSON
Теперь добавим хранение данных в памяти (простой вектор) и реализуем полный REST API для работы с пользователями.
Обновлённый main.cpp:
#include "httplib.h"
#include "json.hpp"
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
using namespace httplib;
using json = nlohmann::json;
// Модель пользователя
struct User {
int id;
std::string name;
std::string email;
};
// База данных в памяти
std::vector<User> users;
int next_id = 1;
int main() {
Server svr;
// POST /users - создать пользователя
svr.Post("/users", [](const Request& req, Response& res) {
try {
auto data = json::parse(req.body);
User u;
u.id = next_id++;
u.name = data["name"];
u.email = data["email"];
users.push_back(u);
json response = {{"id", u.id}, {"name", u.name}, {"email", u.email}};
res.set_content(response.dump(), "application/json");
} catch (...) {
res.status = 400;
res.set_content("{\"error\":\"Invalid JSON\"}", "application/json");
}
});
// GET /users - список всех пользователей
svr.Get("/users", [](const Request& req, Response& res) {
json response = json::array();
for (const auto& u : users) {
response.push_back({{"id", u.id}, {"name", u.name}, {"email", u.email}});
}
res.set_content(response.dump(), "application/json");
});
// GET /users/{id} - получить одного пользователя
svr.Get(R"(/users/(\d+))", [](const Request& req, Response& res) {
int id = std::stoi(req.matches[1]);
for (const auto& u : users) {
if (u.id == id) {
json response = {{"id", u.id}, {"name", u.name}, {"email", u.email}};
res.set_content(response.dump(), "application/json");
return;
}
}
res.status = 404;
res.set_content("{\"error\":\"User not found\"}", "application/json");
});
// PUT /users/{id} - обновить пользователя
svr.Put(R"(/users/(\d+))", [](const Request& req, Response& res) {
int id = std::stoi(req.matches[1]);
try {
auto data = json::parse(req.body);
for (auto& u : users) {
if (u.id == id) {
u.name = data["name"];
u.email = data["email"];
json response = {{"id", u.id}, {"name", u.name}, {"email", u.email}};
res.set_content(response.dump(), "application/json");
return;
}
}
res.status = 404;
res.set_content("{\"error\":\"User not found\"}", "application/json");
} catch (...) {
res.status = 400;
res.set_content("{\"error\":\"Invalid JSON\"}", "application/json");
}
});
// DELETE /users/{id} - удалить пользователя
svr.Delete(R"(/users/(\d+))", [](const Request& req, Response& res) {
int id = std::stoi(req.matches[1]);
auto it = std::remove_if(users.begin(), users.end(), [id](const User& u) {
return u.id == id;
});
if (it != users.end()) {
users.erase(it, users.end());
res.set_content("{\"status\":\"deleted\"}", "application/json");
} else {
res.status = 404;
res.set_content("{\"error\":\"User not found\"}", "application/json");
}
});
std::cout << "REST API Server started on http://localhost:8080"