The Streaming API pattern is used when clients need continuous, real-time updates without polling. Instead of repeatedly calling GET /resource for updates, clients maintain a persistent connection over which the server can push:

  • Events
  • Messages
  • State deltas
  • Notifications
  • Data streams

This pattern includes:

  • Server-Sent Events (SSE) - one-way stream from server to client
  • WebSockets - bi-directional message stream
  • gRPC Streaming - bi-directional, strongly typed message streams (primarily non-HTTP/REST)

12.1. Overview

Streaming APIs:

  • Maintain long-lived connections
  • Push data as it becomes available
  • Reduce latency for UI and systems integrations
  • Remove polling overhead
  • Are ideal for real-time dashboards, collaboration tools, event feeds, chat systems, sensor streams, and dynamic UIs

They differ by communication model:

Streaming Style Direction Transport Typical Use Cases
SSE Server Client HTTP (text/event-stream) Event updates, dashboards, logs
WebSockets Bidirectional WS/WSS Chat, real-time collaboration, IoT control
gRPC Streaming Bidirectional HTTP/2 Typed, high-performance enterprise or microservice communication

12.2. When to Use the Streaming Pattern

Use streaming when:

  • You need sub-second latency for updates
  • Polling creates unnecessary load
  • Many clients subscribe to frequent small updates
  • Data naturally forms a stream (prices, metrics, logs, events)
  • You are building interactive or collaborative experiences

Use Streaming APIs when you need:

  • Continuous, real-time updates
  • Minimal latency
  • Push-based notifications
  • Bidirectional communication (WebSockets)
  • High-frequency event feeds (SSE)

Examples:

  • Price tickers
  • Live dashboards
  • Real-time order/tracking updates
  • Device/sensor telemetry
  • Chat and messaging
  • Pair programming or co-browsing UIs

12.3. When NOT to Use This Pattern

Avoid streaming when:

  • Clients do not benefit from real-time updates
  • Firewalls or infrastructure do not support long-lived connections
  • Message volume is too low to justify streaming
  • The backend cannot support persistent connections at scale
  • Strong delivery guarantees are required (consider message queues instead)
  • The consumer cannot maintain state needed for streaming

Also avoid streaming for:

  • Event-triggered notifications that don’t require constant updates (use Webhooks)
  • Back-office workflows that don’t need immediacy
  • Low-frequency updates
  • Highly sensitive updates that require guaranteed delivery
  • Long-lived connections that backend infrastructure cannot support at scale

12.4. What the Pattern Looks Like

Server-Sent Events (SSE)

  • One-way streaming from server to client
  • Uses HTTP with text/event-stream
  • Auto-reconnect built into browsers

Example Request:

GET /events/orders
Accept: text/event-stream

Example Server Push:

event: order.shipped
data: {"orderId":"or_12345","when":"2024-05-01T10:00:00Z"}

WebSockets

  • Bi-directional messaging
  • Useful for chat, game UIs, collaborative apps
  • Client upgrades from HTTP to WS/WSS

Example Upgrade:

GET /ws/chat → Upgrade: websocket Then messages flow both ways.

gRPC Streaming

  • Multi-stream, type-safe
  • Ideal for inter-service communication
  • Not well expressed through OpenAPI
  • High performance and supports client, server, and bidirectional streaming

12.5. Anti-Patterns to Avoid

  • Replacing every API with streaming: Only use streaming when real-time requirements exist.
  • Using WebSockets when SSE is enough: If clients only need server client messages, SSE is simpler and more scalable.
  • Pushing massive payloads: Streaming is for small, frequent messages.
  • No heartbeat or keep-alive strategy: Leads to broken connections and false “client disconnected” states.
  • Coupling streaming format to backend implementation: Keep message schemas stable and versioned like any other API.

12.6. OpenAPI Examples

OpenAPI 3.x can represent SSE (but not full WebSockets), so we’ll document the SSE version.

openapi: 3.0.3
info:
  title: Orders Events Stream API - Streaming Pattern Example
  version: 1.0.0
servers:
  - url: https://api.example.com
paths:
  /events/orders:
    get:
      summary: Stream order-related events using SSE
      tags: [Events]
      parameters:
        - in: query
          name: eventTypes
          required: false
          schema:
            type: array
            items:
              type: string
          example: ["order.shipped", "order.cancelled"]
      responses:
        '200':
          description: SSE stream of order events
          content:
            text/event-stream:
              schema:
                $ref: '#/components/schemas/OrderEvent'
              examples:
                default:
                  value: |
                    event: order.shipped
                    data: {"orderId":"or_12345","when":"2024-05-01T10:00:00Z"}
components:
  schemas:
    OrderEvent:
      type: object
      properties:
        eventType:
          type: string
          example: "order.shipped"
        data:
          type: object
          example:
            orderId: "or_12345"
            when: "2024-05-01T10:00:00Z"
      required:
        - eventType
        - data

Note: SSE does not use JSON payload wrapping — each event is a text block with fields like event: and data:.

12.7. Visualizing the Streaming Pattern (Mermaid)

A. SSE (One-Way Server Push)

sequenceDiagram
    autonumber
    participant C as Client (Browser/App)
    participant API as Events API
    participant ES as Event Source
    Note over C,API: Establish SSE connection
    C->>API: GET /events/orders\nAccept: text/event-stream
    API-->>C: 200 OK (stream open)
    Note over ES,API: Backend emits events
    ES->>API: publish(order.shipped)
    API-->>C: event: order.shipped\ndata: {...}
    ES->>API: publish(order.cancelled)
    API-->>C: event: order.cancelled\ndata: {...}
    Note over C: Client auto-reconnects if connection drops

B. WebSockets (Bidirectional Streaming)

sequenceDiagram
    autonumber
    participant C as Client
    participant API as WS Gateway
    participant BS as Backend Service
    Note over C,API: WebSocket upgrade handshake
    C->>API: GET /ws/chat\nUpgrade: websocket
    API-->>C: 101 Switching Protocols
    Note over C,API: Bidirectional messaging begins
    C->>API: {"type":"sendMessage","text":"Hello!"}
    API->>BS: forward message
    BS-->>API: {"type":"messageReceived","user":"Alice","text":"Hello!"}
    API-->>C: {"type":"messageReceived","user":"Alice","text":"Hello!"}
    Note over C,API: Connection stays open for real-time communication