howdy/stream
Response bodies written a piece at a time, so each piece reaches the client as soon as it is ready: a large CSV export, a log being tailed, the tokens of a language model as they arrive.
import howdy/stream
controller.get("/users.csv", fn(_ctx) {
response.new(200)
|> response.set_header("content-type", "text/csv")
|> stream.body(fn(writer) {
use writer <- result.try(stream.send_text(writer, "id,name\n"))
list.try_fold(users(), writer, fn(writer, user) {
stream.send_text(writer, user.id <> "," <> user.name <> "\n")
})
})
})
The function runs once the headers have gone, in the connection’s own
process. Each send hands back the writer for the next one. Returning
Ok ends the body. Returning Error stops writing and closes the
connection without ending the body, so the client can tell it was cut
short; the error is logged unless it came from a send that failed
because the client had gone.
For messages pushed to a browser over time, use howdy/sse instead.
In tests, howdy/testing.text and testing.bytes read a streamed body
in full.
Types
Values
pub fn body(
response: response.Response(a),
write: fn(Writer) -> Result(Writer, e),
) -> response.Response(content.Content)
Set the body of response to one written by write, a piece at a
time. Any body already set is replaced.
pub fn send(
writer: Writer,
bits: BitArray,
) -> Result(Writer, content.SendError)
Send bits to the client now.
pub fn send_text(
writer: Writer,
text: String,
) -> Result(Writer, content.SendError)
Send text to the client now, as UTF-8.