documentation/topics/use-subscriptions-with-graphql.md

# Using Subscriptions

You can do this with Absinthe directly, and use
`AshGraphql.Subscription.query_for_subscription/3`. Here is an example of how
you could do this for a subscription for a single record. This example could be
extended to support lists of records as well.

```elixir
# in your absinthe schema file
subscription do
  field :field, :type_name do
    config(fn
      _args, %{context: %{current_user: %{id: user_id}}} ->
        {:ok, topic: user_id, context_id: "user/#{user_id}"}

      _args, _context ->
        {:error, :unauthorized}
    end)

    resolve(fn args, _, resolution ->
      # loads all the data you need
      AshGraphql.Subscription.query_for_subscription(
        YourResource,
        YourDomain,
        resolution
      )
      |> Ash.Query.filter(id == ^args.id)
      |> Ash.read(actor: resolution.context.current_user)
    end)
  end
end
```

## Subscription DSL (beta)

The subscription DSL is currently in beta and before using it you have to enable
them in your config.

> ### Subscription response order {: .warning}
>
> The order in which the subscription responses are sent to the client is not
> guaranteed to be the same as the order in which the mutations were executed.

```elixir
config :ash_graphql, :subscriptions, true
```

First you'll need to do some setup, follow the the
[setup guide](https://hexdocs.pm/absinthe/subscriptions.html#absinthe-phoenix-setup)
in the absinthe docs, but instead of using `Absinthe.Pheonix.Endpoint` use
`AshGraphql.Subscription.Endpoint`.

By default subscriptions are resolved synchronously as part of the mutation.
This means that a resolver is run for every subscriber that is not deduplicated.
If you have a lot of subscribers you can add the
`AshGraphql.Subscription.Batcher` to your supervision tree, which batches up
notifications and runs subscription resolution out-of-band.

```elixir
  @impl true
  def start(_type, _args) do
    children = [
      ...,
      {Absinthe.Subscription, MyAppWeb.Endpoint},
      AshGraphql.Subscription.Batcher
    ]

    # See https://hexdocs.pm/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: MyAppWeb.Supervisor]
    Supervisor.start_link(children, opts)
  end
```

Afterwards, add an empty subscription block to your schema module.

```elixir
defmodule MyAppWeb.Schema do
  ...

  subscription do
  end
end
```

Now you can define subscriptions on your resource or domain

```elixir
defmodule MyApp.Resource do
  use Ash.Resource,
  data_layer: Ash.DataLayer.Ets,
  extensions: [AshGraphql.Resource]

  graphql do
    subscriptions do
      subscribe :resource_created do
        action_types :create
      end
    end
  end
end
```

For further Details checkout the DSL docs for
[resource](/documentation/dsls/DSL-AshGraphql.Resource.md#graphql-subscriptions)
and [domain](/documentation/dsls/DSL-AshGraphql.Domain.md#graphql-subscriptions)

### Deduplication

By default, Absinthe will deduplicate subscriptions based on the `context_id`.
We use the some of the context like actor and tenant to create a `context_id`
for you.

If you want to customize the deduplication you can do so by adding a actor
function to your subscription. This function will be called with the actor that
subscribes and you can return a more generic actor, this way you can have one
actor for multiple users, which will lead to less resolver executions.

```elixir
defmodule MyApp.Resource do
  use Ash.Resource,
  data_layer: Ash.DataLayer.Ets,
  extensions: [AshGraphql.Resource]

  graphql do
    subscriptions do
      subscribe :resource_created do
        action_types :create
        actor fn actor ->
          if check_actor(actor) do
            %{id: "your generic actor", ...}
          else
            actor
          end
        end
      end
    end
  end
end
```