Abstracting away broadcasted model changes from controllers


I want to broadcast every model change that happens in a controller to its corresponding channel.

For example I have

def index(conn, params = %{"app_id" => app_id, "conversation_id" => conversation_id}, user, _claims) do
    page = Messenger.get_messages(user, conversation_id, params)

    |> Scrivener.Headers.paginate(page)
    |> render("index.json", messages: page.entries)

  def create(conn, params = %{"conversation_id" => conversation_id}, user, _claims) do
    case Messenger.send_message(user, conversation_id, params) do
      {:ok, %{message: message, conversation: conversation}} ->
        payload = Phoenix.View.render(MessageView, "show.json", message: message)

        MessageChannel.broadcast_add(conversation_id, payload)

        |> put_status(:created)
        |> json(payload)
      {:error, type, changeset, _} ->
        |> put_status(:unprocessable_entity)
        |> render(ResendWeb.ChangesetView, "error.json", changeset: changeset)

Notice that I send the exact same response over the channel, as in the HTTP response.

With this approach I have to remember adding the appropriate channel broadcast function calls for every create action.

I am curious to see if anybody has a smart way to abstract this out so that all post requests automatically broadcasts the result of an action to the corresponding channels

1 Like

@chrismccord and I discussed a lot about this and, the way channels+pubsub works, is that the content you publish in your controllers is the content you want to send to your clients, so, by definition, it is something specific to your web UI that you don’t want to abstract away.

If you want to abstract away, I recommend starting your own Phoenix.PubSub and use it for internal messages or use something like Elixir’s Registry. You can then subscribe to your primary source which you will continue pushing over MyEndpoint.broadcast.

1 Like

I see

Perhaps my use of abstracting it away was incorrect. I suppose I’m just looking for a nicer, more elegant way to accomplish the same

1 Like

While somewhat tangential, GraphQL provides a relatively easy way to do this via subscriptions. Subscriptions are something we are still working on at the moment but the general idea is that a given UI would simply subscribe to changes it cares about, and then when any client pushes changes the related subscriptions are triggered.

1 Like

GraphQL is definitely an interesting technology but unfortunately it does not make sense to implement in my current project

1 Like