Cara Streaming API Response Menggunakan Server-Sent Events (SSE)

Ashley Innocent

Ashley Innocent

13 March 2026

Cara Streaming API Response Menggunakan Server-Sent Events (SSE)

Intisari

Gunakan Server-Sent Events (SSE) untuk melakukan streaming respons API melalui HTTP. Kirim Content-Type: text/event-stream dan tulis peristiwa sebagai data: {json}\n\n. SSE berfungsi untuk streaming respons AI, pembaruan progres, dan umpan langsung. Modern PetstoreAPI menggunakan SSE untuk rekomendasi hewan peliharaan AI dan pembaruan status pesanan.

Pendahuluan

API Anda menghasilkan rekomendasi AI untuk hewan peliharaan. Responsnya memakan waktu 10 detik. Apakah Anda membuat pengguna menunggu, atau melakukan streaming hasil saat AI itu dibuat?

Dengan Server-Sent Events (SSE), Anda dapat melakukan streaming respons secara real-time. Pengguna melihat hasil segera setelah AI menghasilkannya, menciptakan pengalaman yang lebih baik.

Modern PetstoreAPI menggunakan SSE untuk rekomendasi hewan peliharaan AI, pembaruan status pesanan, dan perubahan inventaris.

Jika Anda menguji API streaming, Apidog mendukung pengujian dan validasi SSE.

tombol

Dasar-dasar SSE

SSE adalah streaming satu arah berbasis HTTP dari server ke klien.

Format SSE

Content-Type: text/event-stream
Cache-Control: no-cache

data: {"message":"First chunk"}\n\n
data: {"message":"Second chunk"}\n\n
data: {"message":"Third chunk"}\n\n

Setiap peristiwa:

Peristiwa Bernama

event: recommendation
data: {"petId":"019b4132","score":0.95}

event: recommendation
data: {"petId":"019b4127","score":0.89}

event: complete
data: {"total":2}

ID Peristiwa

id: 1
data: {"message":"First"}

id: 2
data: {"message":"Second"}

Klien dapat melanjutkan dari ID terakhir jika terputus.

Menerapkan Server SSE

Contoh Node.js/Express

app.get('/v1/pets/recommendations/stream', async (req, res) => {
  // Set header SSE
  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');

  // Kirim rekomendasi saat dibuat
  const recommendations = await generateRecommendations(req.query.userId);

  for (const rec of recommendations) {
    res.write(`data: ${JSON.stringify(rec)}\n\n`);
    await sleep(100); // Simulasikan penundaan streaming
  }

  // Kirim peristiwa penyelesaian
  res.write(`event: complete\ndata: {"total":${recommendations.length}}\n\n`);
  res.end();
});

Contoh Python/FastAPI

from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import json
import asyncio

app = FastAPI()

@app.get("/v1/pets/recommendations/stream")
async def stream_recommendations(user_id: str):
    async def generate():
        recommendations = await get_recommendations(user_id)

        for rec in recommendations:
            yield f"data: {json.dumps(rec)}\n\n"
            await asyncio.sleep(0.1)

        yield f"event: complete\ndata: {json.dumps({'total': len(recommendations)})}\n\n"

    return StreamingResponse(
        generate(),
        media_type="text/event-stream",
        headers={
            "Cache-Control": "no-cache",
            "Connection": "keep-alive"
        }
    )

Implementasi Klien SSE

JavaScript/Browser

const eventSource = new EventSource(
  'https://petstoreapi.com/v1/pets/recommendations/stream?userId=user-456'
);

eventSource.onmessage = (event) => {
  const data = JSON.parse(event.data);
  displayRecommendation(data);
};

eventSource.addEventListener('complete', (event) => {
  const data = JSON.parse(event.data);
  console.log(`Menerima ${data.total} rekomendasi`);
  eventSource.close();
});

eventSource.onerror = (error) => {
  console.error('Kesalahan SSE:', error);
  eventSource.close();
};

React Hook

import { useEffect, useState } from 'react';

function useSSE(url) {
  const [data, setData] = useState([]);
  const [complete, setComplete] = useState(false);

  useEffect(() => {
    const eventSource = new EventSource(url);

    eventSource.onmessage = (event) => {
      const item = JSON.parse(event.data);
      setData(prev => [...prev, item]);
    };

    eventSource.addEventListener('complete', () => {
      setComplete(true);
      eventSource.close();
    });

    return () => eventSource.close();
  }, [url]);

  return { data, complete };
}

// Penggunaan
function Recommendations({ userId }) {
  const { data, complete } = useSSE(
    `https://petstoreapi.com/v1/pets/recommendations/stream?userId=${userId}`
  );

  return (
    <div>
      {data.map(rec => (
        <PetCard key={rec.petId} pet={rec} />
      ))}
      {!complete && <Spinner />}
    </div>
  );
}

Bagaimana Modern PetstoreAPI Menggunakan SSE

Rekomendasi Hewan Peliharaan AI

Streaming rekomendasi yang dihasilkan AI:

GET /v1/pets/recommendations/stream?userId=user-456
Accept: text/event-stream

event: recommendation
data: {"petId":"019b4132","name":"Fluffy","score":0.95,"reason":"Matches your preference for cats"}

event: recommendation
data: {"petId":"019b4127","name":"Buddy","score":0.89,"reason":"Similar to pets you liked"}

event: complete
data: {"total":2,"processingTime":850}

Pembaruan Status Pesanan

Streaming langkah-langkah pemrosesan pesanan:

GET /v1/orders/019b4132/status/stream
Accept: text/event-stream

data: {"status":"payment_processing","timestamp":"2026-03-13T10:30:00Z"}

data: {"status":"payment_confirmed","timestamp":"2026-03-13T10:30:02Z"}

data: {"status":"preparing_shipment","timestamp":"2026-03-13T10:30:05Z"}

event: complete
data: {"status":"shipped","trackingNumber":"1Z999AA10123456784"}

Perubahan Inventaris

Streaming pembaruan inventaris secara real-time:

GET /v1/inventory/stream
Accept: text/event-stream

event: stock-change
data: {"petId":"019b4132","oldStock":5,"newStock":4}

event: price-change
data: {"petId":"019b4127","oldPrice":299.99,"newPrice":279.99}

Lihat dokumentasi SSE Modern PetstoreAPI.

Menguji SSE dengan Apidog

Apidog mendukung pengujian SSE:

  1. Buat permintaan SSE
  2. Atur Accept: text/event-stream
  3. Hubungkan dan lihat peristiwa secara real-time
  4. Validasi format peristiwa
  5. Uji koneksi ulang

Praktik Terbaik

1. Atur Header yang Tepat

res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
res.setHeader('X-Accel-Buffering', 'no'); // Nonaktifkan buffering nginx

2. Kirim Heartbeat

Jaga koneksi tetap hidup:

const heartbeat = setInterval(() => {
  res.write(': heartbeat\n\n');
}, 15000);

res.on('close', () => clearInterval(heartbeat));

3. Tangani Kesalahan dengan Elegan

eventSource.onerror = (error) => {
  if (eventSource.readyState === EventSource.CLOSED) {
    // Koneksi ditutup, akan otomatis terhubung kembali
  } else {
    // Kesalahan lain
    console.error('Kesalahan SSE:', error);
  }
};

4. Gunakan ID Peristiwa untuk Melanjutkan

let lastEventId = 0;

app.get('/stream', (req, res) => {
  const startId = parseInt(req.headers['last-event-id'] || '0');

  for (let i = startId + 1; i <= 100; i++) {
    res.write(`id: ${i}\ndata: {"message":"Event ${i}"}\n\n`);
  }
});

5. Tutup Koneksi

// Klien
eventSource.addEventListener('complete', () => {
  eventSource.close();
});

// Server
res.on('close', () => {
  // Bersihkan sumber daya
});

Kesimpulan

SSE sangat cocok untuk streaming respons API. Ini lebih sederhana daripada WebSocket untuk komunikasi satu arah, berfungsi melalui HTTP, dan menangani koneksi ulang secara otomatis.

Modern PetstoreAPI menggunakan SSE untuk streaming AI, pembaruan pesanan, dan umpan langsung. Uji endpoint SSE dengan Apidog.

FAQ

Bisakah SSE berfungsi melalui firewall perusahaan?

Ya, SSE menggunakan HTTP/HTTPS standar, sehingga berfungsi melalui sebagian besar firewall dan proksi.

Berapa lama koneksi SSE dapat tetap terbuka?

Tanpa batas waktu, tetapi gunakan heartbeat setiap 15-30 detik untuk menjaga koneksi tetap hidup melalui proksi.

Bisakah saya mengirim data biner melalui SSE?

Tidak, SSE hanya teks. Enkode data biner dengan Base64 atau gunakan WebSocket sebagai gantinya.

Apakah SSE mendukung komunikasi dua arah?

Tidak, SSE hanya dari server ke klien. Klien menggunakan permintaan HTTP biasa untuk komunikasi klien-ke-server.

Berapa banyak koneksi SSE yang dapat dimiliki browser?

Browser membatasi koneksi SSE per domain (biasanya 6). Gunakan multiplexing atau WebSocket untuk banyak koneksi.

Mengembangkan API dengan Apidog

Apidog adalah alat pengembangan API yang membantu Anda mengembangkan API dengan lebih mudah dan efisien.