Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to set the event for when sending SSE via FastAPI/Starlette to have different events on the same stream

I want to send SSE from FastAPI with different events on a single stream
and receive them using HTMX-sse in the browser.

The recommended way is to use sse-starlette.

Full working example at https://devdojo.com/bobbyiliev/how-to-use-server-sent-events-sse-with-fastapi

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Simplified here

import asyncio
import uvicorn
from fastapi import FastAPI, Request

app = FastAPI()

from sse_starlette.sse import EventSourceResponse

STREAM_DELAY = 1  # second

@app.get('/stream')
async def message_stream(request: Request):

    cnt = 0

    async def event_generator():
        while True:
            # If client closes connection, stop sending events
            if await request.is_disconnected():
                break

            cnt += 1

            # note: I would like to define the event name here, too

            yield f"I am the data part {cnt}\nand i am multiline"

            await asyncio.sleep(STREAM_DELAY)

    return EventSourceResponse(event_generator())

This code works fine with one problem.

The EventSourceResponse or event_generator function not allow to define the
event needed by ServerSentEvent further down the code.

The SSE content messages pushed should look like this:

event: EventName
data: The data to push

The event name is optional.

Sending an event name allows the receiver to decide what to do with the message.
(I’m using HTMX https://htmx.org/attributes/hx-sse/ to receive the messages.)

The content sent by this example is

data: I am the data part 1
data: and i am multiline
data: I am the data part 2
data: and i am multiline
data: I am the data part 3
data: and i am multiline
data: I am the data part 4
data: and i am multiline
...

And the data: prefix is added to each content message. I can’t remove it.
Also I can’t add line breaks, each line break creates a new data: prefix.

I would like to send different events on the same stream. The data part need to allow line breaks.

My data should look like this:

event: main
data: I am the data part 1\nand I am multiline

event: subform
data: I am the data part 2\nand I am multiline

event: main
data: I am the data part 3\nand I am multiline

event: subform
data: I am the data part 4\nand I am multiline

How can I get the EventSourceResponse to stop adding a data: prefix,
so that the generator can yield both prefix and context. And send multiline data in one event block?

>Solution :

I found the documentation regarding sse-starlette a bit lacking, but from the examples provided I figured out the following.

To set the event type you have two options:

async def gen():
    # Either a dict
    yield {'event': 'EventName', 'data': 'Event Payload'}
    # Or a ServerSentEvent
    yield ServerSentEvent('Event Payload', event='EventName')

I’m not sure it’s possible to directly send multiline data in a SSE, so I suggest encoding the data. Seems like htmx can accept plain HTML from a SSE, so you can encode your newlines as <br> or similar. Otherwise you could attempt to encode the payload in JSON, but you’d have to decode it on the client again.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading