Fork me on GitHub
Logo

cpr - C++ Requests

cpr is a modern HTTP library for C++, built for people.

User Guide

This project is maintained by Fabian Sauter and Tim Stack

Server-Sent Events (SSE) Support

CPR supports Server-Sent Events (SSE), which allows servers to push real-time updates to clients over HTTP. SSE is a standard for unidirectional server-to-client communication over HTTP, commonly used for notifications, live updates, and streaming data.

Basic Usage

#include <cpr/cpr.h>
#include <iostream>

int main() {
    cpr::Session session;
    session.SetUrl(cpr::Url{"https://example.com/events"});

    // Set up SSE callback
    session.SetServerSentEventCallback(
        cpr::ServerSentEventCallback{
            [](cpr::ServerSentEvent&& event, intptr_t userdata) {
                std::cout << "Event Type: " << event.event << std::endl;
                std::cout << "Data: " << event.data << std::endl;

                if (event.id.has_value()) {
                    std::cout << "ID: " << event.id.value() << std::endl;
                }

                if (event.retry.has_value()) {
                    std::cout << "Retry: " << event.retry.value() << " ms" << std::endl;
                }

                // Return true to continue receiving events, false to stop
                return true;
            }
        }
    );

    cpr::Response response = session.Get();

    std::cout << "Status: " << response.status_code << std::endl;

    return 0;
}

ServerSentEvent Structure

Each SSE event contains the following fields:

struct ServerSentEvent {
    std::optional<std::string> id;    // Event ID for tracking/resumption
    std::string event;                // Event type (default: "message")
    std::string data;                 // Event data
    std::optional<size_t> retry;      // Reconnection time in milliseconds
};

Using with User Data

You can pass custom user data to the SSE callback:

#include <cpr/cpr.h>
#include <iostream>
#include <vector>

int main() {
    std::vector<std::string> received_events;

    cpr::Session session;
    session.SetUrl(cpr::Url{"https://example.com/events"});

    // Pass a pointer to user data
    session.SetServerSentEventCallback(
        cpr::ServerSentEventCallback{
            [](cpr::ServerSentEvent&& event, intptr_t userdata) {
                auto* events = reinterpret_cast<std::vector<std::string>*>(userdata);
                events->push_back(event.data);
                return true;
            },
            reinterpret_cast<intptr_t>(&received_events)
        }
    );

    session.Get();

    std::cout << "Received " << received_events.size() << " events" << std::endl;

    return 0;
}

Conditional Event Processing

You can control when to stop receiving events by returning false from the callback:

#include <cpr/cpr.h>
#include <iostream>

int main() {
    int event_count = 0;

    cpr::Session session;
    session.SetUrl(cpr::Url{"https://example.com/events"});

    session.SetServerSentEventCallback(
        cpr::ServerSentEventCallback{
            [](cpr::ServerSentEvent&& event, intptr_t userdata) {
                int* count = reinterpret_cast<int*>(userdata);
                (*count)++;

                std::cout << "Event #" << *count << ": " << event.data << std::endl;

                // Stop after receiving 10 events
                return *count < 10;
            },
            reinterpret_cast<intptr_t>(&event_count)
        }
    );

    session.Get();

    std::cout << "Processed " << event_count << " events" << std::endl;

    return 0;
}

Using SetOption

SSE callbacks can be set using the SetOption method:

#include <cpr/cpr.h>
#include <iostream>

int main() {
    cpr::Session session;

    session.SetOption(cpr::Url{"https://example.com/events"});
    session.SetOption(
        cpr::ServerSentEventCallback{
            [](cpr::ServerSentEvent&& event, intptr_t /*userdata*/) {
                std::cout << event.data << std::endl;
                return true;
            }
        }
    );

    session.Get();

    return 0;
}

Event Types

SSE events can have different types. By default, events have type "message", but servers can specify custom event types:

session.SetServerSentEventCallback(
    cpr::ServerSentEventCallback{
        [](cpr::ServerSentEvent&& event, intptr_t /*userdata*/) {
            if (event.event == "update") {
                std::cout << "Update: " << event.data << std::endl;
            } else if (event.event == "notification") {
                std::cout << "Notification: " << event.data << std::endl;
            } else {
                std::cout << "Message: " << event.data << std::endl;
            }
            return true;
        }
    }
);

Event IDs and Retry

SSE events can include additional metadata:

std::optional<std::string> last_event_id;

session.SetServerSentEventCallback(
    cpr::ServerSentEventCallback{
        [](cpr::ServerSentEvent&& event, intptr_t userdata) {
            auto* last_id = reinterpret_cast<std::optional<std::string>*>(userdata);

            if (event.id.has_value()) {
                *last_id = event.id.value();
            }

            std::cout << "Data: " << event.data << std::endl;
            return true;
        },
        reinterpret_cast<intptr_t>(&last_event_id)
    }
);

session.Get();

// Use last_event_id to resume from last received event if needed
if (last_event_id.has_value()) {
    session.SetHeader(cpr::Header{{"Last-Event-ID", last_event_id.value()}});
    session.Get();
}

SSE Format

Server-Sent Events follow this text-based format according to the HTML5 specification:

event: custom
id: 123
retry: 5000
data: First line of data
data: Second line of data

Important Notes

Common Use Cases

Real-time Notifications

cpr::Session session;
session.SetUrl(cpr::Url{"https://api.example.com/notifications"});
session.SetServerSentEventCallback(
    cpr::ServerSentEventCallback{
        [](cpr::ServerSentEvent&& event, intptr_t /*userdata*/) {
            if (event.event == "notification") {
                std::cout << "New notification: " << event.data << std::endl;
            }
            return true;  // Keep listening
        }
    }
);
session.Get();

Live Data Streams

cpr::Session session;
session.SetUrl(cpr::Url{"https://api.example.com/stock-prices"});
session.SetServerSentEventCallback(
    cpr::ServerSentEventCallback{
        [](cpr::ServerSentEvent&& event, intptr_t /*userdata*/) {
            if (event.event == "price-update") {
                // Parse JSON data and update UI
                std::cout << "Price update: " << event.data << std::endl;
            }
            return true;
        }
    }
);
session.Get();

Progress Updates

cpr::Session session;
session.SetUrl(cpr::Url{"https://api.example.com/long-running-task/123"});
session.SetServerSentEventCallback(
    cpr::ServerSentEventCallback{
        [](cpr::ServerSentEvent&& event, intptr_t /*userdata*/) {
            if (event.event == "progress") {
                std::cout << "Progress: " << event.data << std::endl;
            } else if (event.event == "complete") {
                std::cout << "Task completed!" << std::endl;
                return false;  // Stop listening
            }
            return true;
        }
    }
);
session.Get();