Post

Streaming Responses

Streaming Responses

With streaming responses becoming ubiquitous across applications today, I wanted to understand what they are and explore the various ways they can be implemented. This blog will explore the why, what, how, and when of streaming responses.

What are Streaming Responses?

Streaming responses allow a server to send data to the client incrementally, as it becomes available, rather than waiting to generate the entire response before sending. This enables faster perceived response times, supports large payloads, and enables real-time data delivery.

Why Use Streaming Responses?

  • Faster Time-to-First-Byte: Clients start receiving data immediately.
  • Efficient for Large Data: Avoids loading entire payloads into memory.
  • Real-Time Updates: Enables server push, live feeds, and event streams.
  • Lower Latency: Useful for APIs returning large files, logs, or progressive results.

Common Use Cases

  • Downloading large files (CSV, logs, media)
  • Real-time dashboards and event feeds
  • Server-Sent Events (SSE) and live notifications
  • Progressive rendering of web pages or reports

Streaming Response Examples: Flask vs Django vs FastAPI


# Flask streaming response example
from flask import Flask, Response

def generate_large_csv():
    yield 'id,name\n'
    for i in range(1, 10001):
        yield f"{i},User {i}\n"

app = Flask(__name__)

@app.route('/download')
def download():
    return Response(generate_large_csv(), mimetype='text/csv')

if __name__ == '__main__':
    app.run(debug=True)
    

WebSocket Streaming Examples

WebSockets provide full-duplex communication channels, enabling real-time bidirectional data streaming between client and server.


# Flask WebSocket with Flask-SocketIO
from flask import Flask
from flask_socketio import SocketIO, emit
import time
import threading

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app, cors_allowed_origins="*")

def background_task():
    """Background task that sends periodic updates"""
    count = 0
    while True:
        time.sleep(1)
        count += 1
        socketio.emit('status_update', 
                     {'data': f'Server time: {time.time()}, Count: {count}'},
                     namespace='/live')

@socketio.on('connect', namespace='/live')
def handle_connect():
    print('Client connected')
    emit('response', {'data': 'Connected to live stream'})

@socketio.on('request_data', namespace='/live')
def handle_request(json):
    print(f'Received request: {json}')
    emit('data_response', {'data': f'Response to: {json["message"]}'})

if __name__ == '__main__':
    # Start background task
    thread = threading.Thread(target=background_task)
    thread.daemon = True
    thread.start()
    
    socketio.run(app, debug=True, port=5000)
    

WebSocket vs HTTP Streaming

FeatureHTTP StreamingWebSockets
DirectionUnidirectional (server → client)Bidirectional
ConnectionRequest-response basedPersistent connection
Use CasesFile downloads, logs, SSEChat, real-time dashboards, gaming
OverheadLower (HTTP headers per request)Higher initial, lower per message
Browser SupportUniversalModern browsers

Best Practices

  • Always set appropriate Content-Type and Content-Disposition headers
  • Use generators to minimize memory usage
  • Handle client disconnects gracefully
  • Avoid long blocking operations in generators
  • For real-time, consider chunked encoding or SSE
  • WebSocket specific:
    • Implement proper connection management
    • Handle reconnections on client side
    • Use heartbeat/ping-pong for connection health
    • Implement authentication and authorization
    • Consider message queuing for reliability

Summary Table

FrameworkHTTP StreamingWebSocket SupportMemory EfficientReal-Time CapableNotes
FlaskResponse (with generator)Flask-SocketIOYesYesSimple, flexible; requires extension for WebSockets
DjangoStreamingHttpResponseDjango ChannelsYesYesSupports file-like objects; ASGI for WebSockets
FastAPIStreamingResponseNative WebSocketYesYesBuilt-in async support, native WebSocket support

References:

This post is licensed under CC BY 4.0 by the author.