Possible to do server side events with deno fresh framework

437 Views Asked by At

Is it possible to use server side events for a fresh POST handler? I have a long server side process and would like to return some event updates to the client meanwhile?

2

There are 2 best solutions below

3
Darren Cook On

The quick answer is no, because SSE does not support POST, only GET. (See https://stackoverflow.com/a/34285526/841830)

1
King Friday On

Absolutely

Deno Fresh Server (v1.6)

import { Handlers } from "$fresh/server.ts";
import { ServerSentEventStream } from "https://deno.land/[email protected]/http/server_sent_event_stream.ts";

export const handler: Handlers = {
  async POST(req: Request) {
    const payload = await req.json()

    // todo: can check payload / auth check here
    // if you use client npm package "fetch-event-source"
    /*
    if (!authorized) {
      return Response.json({
        message: 'not allowed'
      }, { status: 403 })
    }
    */

    const db = await Deno.openKv()

    return new Response(new ReadableStream({
      async start(controller) {
        for await (const [{ value: message }] of db.watch([['your-key']])) {
          controller.enqueue({
            data: JSON.stringify(message),
            id: Date.now(),
            event: 'message'
          })
        }
      },
      cancel() {
        console.log('cancel')
      },
    }).pipeThrough(new ServerSentEventStream()), {
      headers: {
        "Content-Type": "text/event-stream",
      },
    })
  }
}

Client-side

Recommend using npm fetch-event-source on the client part as it allows headers. Sourcing it like so using ISLANDS approach:

import { fetchEventSource } from "https://esm.sh/@microsoft/[email protected]"

Call it with headers and set authorization etc.

fetchEventSource('/api/listen', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${session?.access_token}`
  },
  body: JSON.stringify({
    whatever: 123
  }),
  onopen(resp: Response) {
    console.log('on open')
    return Promise.resolve()
  },
  onmessage(ev) {
    console.log('on message', ev)
  },
  onclose() {
   console.log('on close')
  },
  onerror(err) {
   console.log('on error', err)
  }
})