# Streaming

# Request streaming

Sanic allows you to stream data sent by the client to begin processing data as the bytes arrive.

When enabled on an endpoint, you can stream the request body using await request.stream.read().

That method will return None when the body is completed.

from sanic.views import stream

class SimpleView(HTTPMethodView):
    async def post(self, request):
        result = ""
        while True:
            body = await request.stream.read()
            if body is None:
            result += body.decode("utf-8")
        return text(result)

It also can be enabled with a keyword argument in the decorator...

@app.post("/stream", stream=True)
async def handler(request):
        body = await request.stream.read()

... or the add_route() method.



Only post, put and patch decorators have stream argument.

# Response streaming

Sanic allows you to stream content to the client with an instance of StreamingHTTPResponse. There is also a sanic.response.stream convenience method.

This method accepts a coroutine callback which is passed an object that can control writing to the client.

from sanic.response import stream

async def test(request):
    async def sample_streaming_fn(response):
        await response.write("foo,")
        await response.write("bar")

    return stream(sample_streaming_fn, content_type="text/csv")

This is useful in situations where you want to stream content to the client that originates in an external service, like a database. For example, you can stream database records to the client with the asynchronous cursor that asyncpg provides.

async def index(request):
    async def stream_from_db(response):
        conn = await asyncpg.connect(database='test')
        async with conn.transaction():
            async for record in conn.cursor('SELECT generate_series(0, 10)'):
                await response.write(record[0])

    return stream(stream_from_db)


If a client supports HTTP/1.1, Sanic will use chunked transfer encoding (opens new window); you can explicitly enable or disable it using chunked option of the stream function.

# File streaming

Sanic provides sanic.response.file_stream function that is useful when you want to send a large file. It returns a StreamingHTTPResponse object and will use chunked transfer encoding by default; for this reason Sanic doesn’t add Content-Length HTTP header in the response.

A typical use case might be streaming an video file.

async def handler_file_stream(request):
    return await response.file_stream(
            "Content-Disposition": 'Attachment; filename="nicer_name.meta4"',
            "Content-Type": "application/metalink4+xml",

If you want to use the Content-Length header, you can disable chunked transfer encoding and add it manually.

from aiofiles import os as async_os
from sanic.response import file_stream

async def index(request):
    file_path = "/srv/www/whatever.png"

    file_stat = await async_os.stat(file_path)
    headers = {"Content-Length": str(file_stat.st_size)}

    return await file_stream(
MIT Licensed | Copyright © 2018-present Sanic Community Organization