Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Server-Sent Events (SSE)

aioduct has built-in support for consuming Server-Sent Events streams. SSE is a standard for servers to push events to clients over HTTP, commonly used by LLM APIs (OpenAI, Anthropic) for streaming responses.

Basic Usage

use aioduct::TokioClient;

#[tokio::main]
async fn main() -> Result<(), aioduct::Error> {
    let client = TokioClient::new();

    let resp = client
        .get("http://example.com/events")?
        .send()
        .await?;

    let mut sse = resp.into_sse_stream();
    while let Some(event) = sse.next().await {
        let event = event?;
        println!("event: {:?}, data: {}", event.event, event.data);
    }

    Ok(())
}

SseEvent Fields

Each parsed event contains:

FieldTypeDescription
eventOption<String>Event type (from event: field)
dataStringEvent payload (joined with \n for multi-line)
idOption<String>Event ID (from id: field)
retryOption<u64>Reconnection time in ms (from retry: field)

SSE Wire Format

The SSE protocol uses a simple text-based format where events are separated by blank lines (\n\n):

event: greeting
data: hello

data: line1
data: line2

event: done
data: bye
id: 42
retry: 5000

This produces three events:

  1. SseEvent { event: Some("greeting"), data: "hello", id: None, retry: None }
  2. SseEvent { event: None, data: "line1\nline2", id: None, retry: None }
  3. SseEvent { event: Some("done"), data: "bye", id: Some("42"), retry: Some(5000) }

Comments

Lines starting with : are comments and are silently ignored:

: this is a heartbeat comment
data: actual event

Example: Streaming LLM API

use aioduct::TokioClient;

#[tokio::main]
async fn main() -> Result<(), aioduct::Error> {
    let client = TokioClient::with_rustls();

    let resp = client
        .post("https://api.example.com/v1/chat/completions")?
        .bearer_auth("sk-...")
        .header_str("content-type", "application/json")?
        .body(r#"{"model":"gpt-4","stream":true,"messages":[{"role":"user","content":"Hi"}]}"#)
        .send()
        .await?;

    let mut sse = resp.into_sse_stream();
    while let Some(event) = sse.next().await {
        let event = event?;
        if event.data == "[DONE]" {
            break;
        }
        print!("{}", event.data);
    }

    Ok(())
}