absinthe-graphql / absinthe

The GraphQL toolkit for Elixir
http://absinthe-graphql.org
Other
4.29k stars 527 forks source link

Passing information between triggering mutation and subscriptions #1344

Open martosaur opened 1 month ago

martosaur commented 1 month ago

Suppose we want to create a subscription that would simply publish names of all mutations that were called:

# test/absinthe/execution/subscription_test.exs
  defmodule Schema do
    use Absinthe.Schema

    object :user do
      field :id, :id
      field :name, :string
    end

    subscription do    
      field :all_mutations, :string do
        config fn _, _ -> {:ok, topic: "*"} end
        trigger [:update_user], topic: fn _ -> "*" end
        # None of the input arguments can carry `updateUser` string
        resolve fn _mutation_result, _args, _resolution -> {:ok, "updateUser"} end
      end
    end

    mutation do
      field :update_user, :user do
        arg :id, non_null(:id)

        resolve fn _, %{id: id}, _ ->
          {:ok, %{id: id, name: "foo"}}
        end
      end
    end
  end

  @query """
  subscription {
    allMutations 
  }
  """
  test "can pass context from mutation to subscription" do
    id = "1"

    assert {:ok, %{"subscribed" => topic}} = run_subscription(@query, Schema, context: %{pubsub: PubSub})

    mutation = """
    mutation ($userId: ID!) {
      updateUser(id: $userId) { id name }
    }
    """

    assert {:ok, %{data: _}} =
             run_subscription(mutation, Schema,
               variables: %{"userId" => id},
               context: %{pubsub: PubSub}
             )

    assert_receive({:broadcast, msg})

    assert %{
             event: "subscription:data",
             result: %{data: %{"allMutations" => "updateUser"}},
             topic: topic
           } == msg
  end

If I'm reading the code right, it's not possible with just trigger macro right now. The only piece of information that is passed to a subscription's resolver from a mutation is the mutation's result.

Would it make sense to provide an avenue for passing some arbitrary context between two resolutions? I'm happy to take a stab at implementing this, but not quite sure what would be the best place to put this extra context.