Skip to content

Proposal: Add ergonomic ServerSentEventGenerator API (builder pattern) #10

@jrey8343

Description

@jrey8343

Summary

I'd like to propose adding a higher-level API that abstracts away SSE implementation details, similar to the official Go SDK's datastar.NewSSE() pattern.

Motivation

The current API requires users to:

  1. Create event objects manually (PatchElements::new(), PatchSignals::new())
  2. Call framework-specific conversion methods (.write_as_axum_sse_event())
  3. Wrap in Ok() and yield to the stream

This is verbose and exposes SSE implementation details that most users don't need to think about.

Proposed API

use datastar::axum::sse;

async fn handler(ReadSignals(signals): ReadSignals<Signals>) -> impl IntoResponse {
    Sse::new(stream_fn(move |yielder| async move {
        let mut sse = sse(yielder);

        // Simple, ergonomic methods
        sse.patch_elements("<div id='msg'>Hello</div>").await;
        sse.remove_element("#temp").await;
        sse.patch_signals(r#"{"count": 1}"#).await;
        sse.execute_script("console.log('hi')").await;
        sse.redirect("/dashboard").await;

        // For advanced options, use _with variants
        sse.patch_elements_with(
            PatchElements::new(html)
                .selector("#feed")
                .mode(ElementPatchMode::After)
        ).await;
    }))
}

Comparison with Go SDK

The Go SDK provides this pattern:

sse := datastar.NewSSE(w, r)
sse.PatchElements(html)
sse.RemoveElement("#temp")
sse.MarshalAndPatchSignals(map[string]any{"count": 1})
sse.ExecuteScript(`console.log("hello")`)
sse.Redirect("/new-page")

Implementation Approach

  • Add ServerSentEventGenerator<Y> struct with an SseYielder trait
  • Add framework-specific yielder wrappers (AxumYielder, WarpYielder)
  • Add sse() factory functions in each framework module
  • Add asynk-strim as an optional dependency behind a feature flag
  • Fully backward compatible - existing API remains unchanged

Questions

  • Does this align with the direction you'd like for the SDK?
  • Any concerns about adding asynk-strim as a dependency?
  • Naming preferences? (ServerSentEventGenerator matches Go, or something shorter?)

I have a working implementation ready if you're interested.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions