Using Server-Sent Events (SSE)
Server-Sent Events (SSE) is a web technology that enables a server to push real-time updates to HttpCommand. Unlike WebSockets, which provide full-duplex communication, SSE is unidirectional — data flows only from server to client. HttpCommand initiates the connection with a standard HTTP request, and the server responds with a text/event-stream content type, keeping the connection open and sending data as a stream of newline-delimited messages. Each message can include fields such as data, event, id, and retry. SSE is particularly well-suited for use cases like live feeds, log streaming, and AI chat completions, where the server needs to continuously deliver updates without the client repeatedly polling.
Basic steps to use SSE
- Write a dyadic, non-result-returning function to process the event messages from the server. We'll call this function the "SSE handler".
- The right argument is the event payload.
- The left argument is a reference to the
HttpCommandresult namespace. - If you do not write an SSE handler, the event message will be displayed to the APL session.
- Create an instance of
HttpCommand. For example:h←HttpCommand.New '' - Set
URLto the address of the host server. - Set
EnableSSEto1. - Set
OnSSEfnto the name of the function you wrote. - If you do not want
HttpCommandto parse the event messages into a namespace format, setParseSSEto0. - Run the
HttpCommandinstance, saving the reference to the result namespace. For example:r←h.Run
This will start a listener on a separate thread. - Every time an event message is received,
HttpCommandwith pass either:- If
ParseSSEis0, the unmodified event message is passed as the right argument to the SSE handler. - If
ParseSSEis1, the a namespace containing the parsed event message is passed as the right argument to the SSE handler.
- If
- To stop the listener you can either hit interrupt or use the
Closefunction in the result namespace. For example:r.Close. - You can also append the raw SSE event messages to a file by specifying
OutFileand optionallyMaxPayloadSize. If you specifyMaxPayloadSize, the listener will quit when appending the current event message would exceedMaxPayloadsize.
Handling SSE Event Messages
When the listener receives an SSE event message it will:
- If
OutFileis specified, append the raw event message to the file specified byOutFile - If
ParseSSEis1(the default), the event message is parsed based on the SSE specification into a namespace format that's more useful in an APL environment. The namespace contains:event- the event name, or'message'ifevent:was not specified in the event messagedata- a vector of character vectors, one per occurrence ofdata:in the event messageid- theid:of the event message or''ifid:was not specifiedretry- if specified in the event message, the reconnection time in milliseconds. Note that the current architecture is not able to do anything withretry.
- If you have specified
OnSSEfn, it is called passing:- a reference to the
HttpCommandresult namespace as its left argument - as its right argument - the namespace described above if
ParseSSE←1or the raw event message ifParseSSE←0
- a reference to the
- If you have not specified
OnSSEfnthe event message is displayed in the session.
To stop the listener you can either call r.Close or generate an interrupt.
HttpCommand Result Namespace Modifications
If you're using SSE, the HttpCommand result namespace has some additional elements:
SSEThreadis the thread on which the listener is runningCloseis a function to terminate the listenerCloseSSEis a Boolean which the listener checks for whether to terminate or not. TheClosefunction setsCloseSSE←1- Additionally, the display format of the result namespace is updated whenever
msg,rc,HttpStatus, orHttpMessageare updated.
Example
h←HttpCommand.New (
URL:'https://echo.websocket.org/.sse'
)
h.Run
[rc: ¯1 | msg: Server responded with SSE, but EnableSSE=0 | HTTP Status: 200 "OK" | ≢Data: 0]
Duh! Need to set EnableSSE←1
onSSE←{
⍝ ⍺ - reference to HttpCommand result namespace
⍝ ⍵ - SSE payload
'10'≡⍵.id: ⍺.Close ⍝ close listener when we get to id='10'
⍵.(event id) ⍝ otherwise display the event and id
}
h←HttpCommand.New (
URL:'https://echo.websocket.org/.sse'
EnableSSE:1
OnSSEfn:'onSSE'
)
r←h.Run
server 1
request 2
time 3
time 4
time 5
time 6
time 7
time 8
time 9