Crow для C++: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Crow — микровеб-фреймворк для C++

1. Что это и зачем нужна

Crow — это легковесный, быстрый и современный микровеб-фреймворк для языка C++, вдохновлённый популярным Python-фреймворком Flask. Он предназначен для создания REST API, веб-сервисов и простых веб-приложений с минимальным количеством кода и без необходимости в сложной настройке. Crow написан на C++17/20 и использует библиотеки asio (или boost.asio) для асинхронной обработки запросов, что делает его одним из самых производительных решений в своей нише.

Зачем использовать Crow? Если вам нужно быстро развернуть HTTP-сервер на C++ для обработки JSON-запросов, отдачи статики или создания микросервиса, Crow — идеальный выбор. В отличие от тяжеловесных фреймворков вроде drogon или pistache, Crow имеет минимальный размер, простой API и не требует генерации кода или сложных макросов. Он отлично подходит для встраиваемых систем, IoT-устройств, игровых серверов и любых сценариев, где важна скорость и низкое потребление памяти.

Crow поддерживает маршрутизацию (включая динамические параметры в URL), middleware, работу с JSON (через встроенную библиотеку или nlohmann/json), WebSocket, CORS, multipart/form-data и многое другое. Фреймворк активно развивается, имеет хорошую документацию и стабильное комьюнити.

2. Установка

Crow — header-only библиотека (в большинстве случаев), поэтому установка сводится к клонированию репозитория и подключению заголовочных файлов. Однако для сборки примеров и проектов рекомендуется использовать CMake.

Способ 1: Клонирование (рекомендуется для разработки)

git clone https://github.com/CrowCpp/Crow.git
cd Crow
mkdir build
cd build
cmake ..
make
sudo make install

Способ 2: Использование vcpkg

vcpkg install crow

Способ 3: Подключение через CMake FetchContent

include(FetchContent)
FetchContent_Declare(
    crow
    GIT_REPOSITORY https://github.com/CrowCpp/Crow.git
    GIT_TAG v1.0.0
)
FetchContent_MakeAvailable(crow)

target_link_libraries(your_project PRIVATE Crow::Crow)

Важно: Crow требует компилятор с поддержкой C++17 (gcc 8+, clang 7+, MSVC 2019+). Также необходима библиотека asio (или boost.asio). Если вы используете vcpkg, зависимости подтянутся автоматически.

3. Быстрый старт — минимальный рабочий пример

Создайте файл main.cpp со следующим содержимым:

#include "crow.h"

int main() {
    crow::SimpleApp app;

    // Определяем маршрут для корневого URL
    CROW_ROUTE(app, "/")([](){
        return "Hello, Crow!";
    });

    // Запускаем сервер на порту 8080
    app.port(8080).multithreaded().run();
}

Скомпилируйте и запустите:

g++ -std=c++17 -pthread main.cpp -o crow_server
./crow_server

Откройте браузер и перейдите на http://localhost:8080. Вы увидите приветственное сообщение.

4. Основные методы/функции/классы

4.1. crow::SimpleApp

Сигнатура: class SimpleApp : public crow::App<Middleware...>

Что делает: Основной класс приложения. Управляет маршрутами, middleware и жизненным циклом сервера. SimpleApp — это предварительно сконфигурированная версия App с минимальным набором middleware.

crow::SimpleApp app;
app.port(8080).run();

4.2. CROW_ROUTE (макрос)

Сигнатура: CROW_ROUTE(app, url)

Что делает: Регистрирует обработчик для указанного URL. Поддерживает динамические параметры (например, /user/<int>).

CROW_ROUTE(app, "/hello/<string>")([](const std::string& name){
    return crow::response("Hello, " + name);
});

4.3. crow::response

Сигнатура: response(int code, const std::string& body) или response(const std::string& body)

Что делает: Создаёт HTTP-ответ с заданным кодом и телом. Можно также устанавливать заголовки, тип контента и т.д.

CROW_ROUTE(app, "/json")([](){
    crow::json::wvalue x;
    x["message"] = "Hello, JSON!";
    return crow::response(x);
});

4.4. crow::request

Сигнатура: const crow::request& req (передаётся как параметр в обработчик)

Что делает: Представляет входящий HTTP-запрос. Содержит URL, метод, заголовки, тело, параметры запроса и т.д.

CROW_ROUTE(app, "/info")([](const crow::request& req){
    std::string method = req.method;
    std::string user_agent = req.get_header_value("User-Agent");
    return crow::response("Method: " + method + ", UA: " + user_agent);
});

4.5. crow::json::wvalue / crow::json::rvalue

Сигнатура: crow::json::wvalue (для записи), crow::json::rvalue (для чтения)

Что делает: Встроенная библиотека для работы с JSON. wvalue используется для создания JSON-объектов, rvalue — для парсинга входящих JSON-данных.

// Создание JSON
crow::json::wvalue json;
json["name"] = "Alice";
json["age"] = 30;
json["items"] = {"apple", "banana"};

// Чтение JSON из запроса
CROW_ROUTE(app, "/parse").methods("POST"_method)([](const crow::request& req){
    auto body = crow::json::load(req.body);
    if (!body) return crow::response(400, "Invalid JSON");
    std::string name = body["name"].s();
    return crow::response("Hello, " + name);
});

4.6. app.port() / app.bindaddr()

Сигнатура: App& port(uint16_t port) / App& bindaddr(const std::string& addr)

Что делает: Устанавливает порт и IP-адрес для прослушивания. По умолчанию — 0.0.0.0:80.

app.port(3000).bindaddr("127.0.0.1").run();

4.7. app.multithreaded()

Сигнатура: App& multithreaded()

Что делает: Включает многопоточную обработку запросов. Использует пул потоков (по умолчанию количество потоков равно числу ядер CPU).

app.port(8080).multithreaded().run();

4.8. app.loglevel()

Сигнатура: App& loglevel(crow::LogLevel level)

Что делает: Устанавливает уровень логирования. Доступные уровни: Debug, Info, Warning, Error, Critical.

app.loglevel(crow::LogLevel::Warning); // Показывать только предупреждения и ошибки

4.9. crow::mustache::load (шаблонизатор)

Сигнатура: mustache::template_t load(const std::string& filename)

Что делает: Загружает шаблон Mustache и рендерит его с переданными данными. Шаблоны должны находиться в папке templates/.

CROW_ROUTE(app, "/page")([](){
    crow::mustache::template_t page = crow::mustache::load("index.html");
    crow::json::wvalue ctx;
    ctx["title"] = "My Page";
    return page.render(ctx);
});

4.10. CROW_CATCHALL_ROUTE

Сигнатура: CROW_CATCHALL_ROUTE(app)

Что делает: Определяет обработчик для всех не найденных маршрутов (404).

CROW_CATCHALL_ROUTE(app)([](){
    return crow::response(404, "Not Found");
});

5. Реальный практический пример (100-200 строк кода)

Ниже представлен полноценный REST API для управления списком задач (Todo List) с поддержкой CRUD операций, хранением в памяти и валидацией.

#include "crow.h"
#include <unordered_map>
#include <mutex>
#include <string>

struct Task {
    int id;
    std::string title;
    bool completed;
};

class TodoAPI {
private:
    std::unordered_map<int, Task> tasks;
    int next_id = 1;
    std::mutex mtx;

public:
    TodoAPI(crow::SimpleApp& app) {
        // GET /tasks — получить все задачи
        CROW_ROUTE(app, "/tasks").methods("GET"_method)([this](){
            std::lock_guard<std::mutex> lock(mtx);
            crow::json::wvalue list;
            int index = 0;
            for (const auto& [id, task] : tasks) {
                crow::json::wvalue item;
                item["id"] = task.id;
                item["title"] = task.title;
                item["completed"] = task.completed;
                list[index++] = std::move(item);
            }
            return crow::response(list);
        });

        // POST /tasks — создать задачу
        CROW_ROUTE(app, "/tasks").methods("POST"_method)([this](const crow::request& req){
            auto body = crow::json::load(req.body);
            if (!body || !body.has("title")) {
                return crow::response(400, "Missing 'title' field");
            }

            std::lock_guard<std::mutex> lock(mtx);
            Task new_task{next_id++, body["title"].s(), false};
            tasks[new_task.id] = new_task;

            crow::json::wvalue res;
            res["id"] = new_task.id;
            res["title"] = new_task.title;
            res["completed"] = new_task.completed;
            return crow::response(201, res);
        });

        // GET /tasks/{id} — получить задачу по ID
        CROW_ROUTE(app, "/tasks/<int>").methods("GET"_method)([this](int id){
            std::lock_guard<std::mutex> lock(mtx);
            auto it = tasks.find(id);
            if (it == tasks.end()) {
                return crow::response(404, "Task not found");
            }

            crow::json::wvalue res;
            res["id"] = it->second.id;
            res["title"] = it->second.title;
            res["completed"] = it->second.completed;
            return crow::response(res);
        });

        // PUT /tasks/{id} — обновить задачу
        CROW_ROUTE(app, "/tasks/<int>").methods("PUT"_method)([this](int id, const crow::request& req){
            auto body = crow::json::load(req.body);
            if (!body) {
                return crow::response(400, "Invalid JSON");
            }

            std::lock_guard<std::mutex> lock(mtx);
            auto it = tasks.find(id);
            if (it == tasks.end()) {
                return crow::response(404, "Task not found");
            }

            if (body.has("title")) it->second.title = body["title"].s();
            if (body.has("completed")) it->second.completed = body["completed"].b();

            crow::json::wvalue res;
            res["id"] = it->second.id;
            res["title"] = it->second.title;
            res["completed"] = it->second.completed;
            return crow::response(res);
        });

        // DELETE /tasks/{id} — удалить задачу
        CROW_ROUTE(app, "/tasks/<int>").methods("DELETE"_method)([this](int id){
            std::lock_                    

Рекомендаций