Skip to content

Server-Sent Events (SSE)

Learn how to implement Server-Sent Events in Iris.

Basic SSE Implementation

go
package main

import (
    "time"
    "github.com/kataras/iris/v12"
)

func main() {
    app := iris.New()

    app.Get("/events", func(ctx iris.Context) {
        ctx.ContentType("text/event-stream")
        ctx.Header("Cache-Control", "no-cache")
        ctx.Header("Connection", "keep-alive")

        // Send events every second
        ctx.StreamWriter(func(w *bufio.Writer) bool {
            msg := fmt.Sprintf("data: {\"time\": \"%v\"}\n\n", time.Now().Unix())
            w.WriteString(msg)
            w.Flush()
            time.Sleep(time.Second)
            return true
        })
    })

    app.Listen(":8080")
}

Custom Event Types

go
app.Get("/custom-events", func(ctx iris.Context) {
    ctx.ContentType("text/event-stream")
    ctx.Header("Cache-Control", "no-cache")
    ctx.Header("Connection", "keep-alive")

    ctx.StreamWriter(func(w *bufio.Writer) bool {
        // Send different event types
        events := []struct {
            Type    string
            Data    string
            ID      string
            Retry   int
        }{
            {
                Type: "user",
                Data: `{"name": "John"}`,
                ID:   "1",
            },
            {
                Type: "notification",
                Data: `{"message": "New message"}`,
                ID:   "2",
            },
        }

        for _, event := range events {
            if event.Type != "" {
                w.WriteString(fmt.Sprintf("event: %s\n", event.Type))
            }
            if event.ID != "" {
                w.WriteString(fmt.Sprintf("id: %s\n", event.ID))
            }
            if event.Retry > 0 {
                w.WriteString(fmt.Sprintf("retry: %d\n", event.Retry))
            }
            w.WriteString(fmt.Sprintf("data: %s\n\n", event.Data))
            w.Flush()
            time.Sleep(time.Second)
        }

        return true
    })
})

Error Handling

go
app.Get("/events-with-error", func(ctx iris.Context) {
    ctx.ContentType("text/event-stream")
    ctx.Header("Cache-Control", "no-cache")
    ctx.Header("Connection", "keep-alive")

    ctx.StreamWriter(func(w *bufio.Writer) bool {
        select {
        case <-ctx.Request().Context().Done():
            // Client disconnected
            return false
        case err := <-getErrorChannel():
            // Handle error
            w.WriteString(fmt.Sprintf("event: error\ndata: %v\n\n", err))
            w.Flush()
            return false
        default:
            // Send normal event
            w.WriteString(fmt.Sprintf("data: {\"time\": \"%v\"}\n\n", time.Now().Unix()))
            w.Flush()
            time.Sleep(time.Second)
            return true
        }
    })
})

Best Practices

  1. Implementation:

    • Set proper headers
    • Handle disconnects
    • Monitor connections
    • Clean resources
    • Handle errors
  2. Performance:

    • Buffer appropriately
    • Monitor memory
    • Handle backpressure
    • Optimize events
    • Regular cleanup
  3. Security:

    • Validate clients
    • Monitor usage
    • Handle timeouts
    • Set rate limits
    • Control access
  4. Maintenance:

    • Monitor connections
    • Handle reconnects
    • Regular testing
    • Document usage
    • Review performance

Built with excellence by Hellenic Development, delivering enterprise-grade solutions.