# `VerifiedPubSub.Api`
[🔗](https://github.com/CuriousCurmudgeon/verified_pubsub/blob/v0.1.0/lib/verified_pubsub/api.ex#L1)

The call-site API: `subscribe/2`, `unsubscribe/2`, `topic/2`, `broadcast/4`,
`broadcast!/4`, `broadcast_from/5` and `broadcast_from!/5`.

`use VerifiedPubSub, manifest: MyApp.Topics` imports these macros, and so does
`use VerifiedPubSub.Subscriber`:

    broadcast!(:pets, %{owner_id: id}, :adopted, payload)

## Argument order

In every macro here, the params come immediately after the topic. The params only fill
in the segments of the topic, so `{topic, params}` is the address and `{event, payload}`
is the message. `Phoenix.PubSub.broadcast/3` has the same order: the address, then the
message. Also, the two atoms are never next to each other, so a call site cannot swap
them without notice.

## Why macros rather than functions

These are **macros**, so the topic and the event must be literal atoms. Because of this,
an unknown topic or event is a `CompileError` that names the valid choices. A call site
can build the params at runtime. The macro checks a literal params map at compile time.
A params map built at runtime raises `KeyError` from `Map.fetch!/2` when a key is
missing.

A plain function that takes atoms gets no check at compile time. Elixir's type inference
does not narrow across clause heads on a remote call. So a `broadcast/4` defined as

    def broadcast(:pets, %{owner_id: id}, :adopted, payload), do: ...

gives **no diagnostic at all** for `broadcast(:pets, params, :adoptd, ...)`. We checked
this on Elixir 1.20.4. The call fails at runtime instead. A macro can find the topic and
the event in the manifest while your code compiles.

The macros have these costs:

  * each module that calls them needs the import
  * a pipe cannot pass a value into them
  * `&` cannot capture them
  * `apply/3` cannot call them

## Broadcasts that skip the sender

`broadcast_from/5` and `broadcast_from!/5` work like `Phoenix.PubSub.broadcast_from/4`.
`from` comes first for the same reason that it does there:

    broadcast_from!(self(), :pets, %{owner_id: id}, :adopted, payload)

A common use is a LiveView that writes to a topic and also subscribes to it. Without
these macros, the LiveView applies its own change twice.

`from` is the pid that you pass, so `self()` is the process that makes the call. When a
context function, a `Task`, or an Oban job makes the broadcast, `self()` is *that*
process, not the process that started the request. In that case, pass the pid of the
process that started the request.

# `broadcast`
*macro* 

Broadcasts an event on a topic that takes no params.

It is the same as `broadcast(topic, %{}, event, payload)`. When the topic takes params,
the call is a compile error. `subscribe/1` works the same way.

# `broadcast`
*macro* 

Broadcasts an event on a topic.

# `broadcast!`
*macro* 

Broadcasts an event on a topic that takes no params, and raises on failure.

# `broadcast!`
*macro* 

Broadcasts an event on a topic, and raises on failure.

# `broadcast_from`
*macro* 

Broadcasts on a topic that takes no params, to every subscribed process except `from`.

# `broadcast_from`
*macro* 

Broadcasts to every subscribed process except `from`.

# `broadcast_from!`
*macro* 

Broadcasts on a topic that takes no params, to every subscribed process except `from`,
and raises on failure.

# `broadcast_from!`
*macro* 

Broadcasts to every subscribed process except `from`, and raises on failure.

# `subscribe`
*macro* 

Subscribes the current process to a topic.

# `topic`
*macro* 

Returns the wire topic.

# `unsubscribe`
*macro* 

Unsubscribes the current process from a topic.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
