zgore

zgore

Is there a way to give an `Absinthe.Resolution` structure to `trigger/2` function's callback?

Hello world!

I’m currently working around Absinthe subscriptions feature, and I come with a question on trigger/2. And I was wondering if :

Is there a way to give an Absinthe.Resolution structure to the topic callback function which is given as second parameter of the trigger/2 function ?

I might be missing something, but in my opinion, as the config/2 function callback receives the resolution structure as second parameter, which allows us to create subscription topic based on some context content; I would have expected the trigger topic callback to do the same.

I will expose the problem which leds me to this question, and the solution I found to overcome it.

Problem

I would like to create a subscription on a rule type and trigger it when a rule is created.
I want this subscription to be triggered on an tenant_id topic which is obtained from the context in the resolution structure passed in parameter of the config/2 function’s callback.

Instead of using publish/3 in my resolver, I would like to use the trigger/2 function to centralize all my trigger definitions.

Therefore, I have this mutation:

mutation do
    field :create_rule, non_null(:rule) do
      arg(:rule, non_null(:create_rule_input))

      resolve(&RuleResolver.create_rule/3)
    end
end

And this subscription configured :

subscription do
    field :rule, :rule do
      config(fn 
      _args, %{context: %{current_tenant: %{id: tenant_id}}} ->
        {:ok, topic: tenant_id}
      _, _ ->
        ErrorResolver.resolve(:forbidden)
    end)

      trigger(:create_rule,
        topic: fn rule ->
          rule.tenant_id
        end
      )
    end
end

Here, i’m using the tenant_id contained in the rule structure I return to determine the topic and to make it work.

But, tomorrow, if I have another structure which doesn’t contains this tenant_id, I could not use the same logic as above. More over, I cannot retrieve it from the context in the resolution since it’s not accessible in the trigger.

Potential Solution

To make sure any trigger can determine a topic based on the tenant_id without worrying about the fact that this id is contained or not in the result structure, I modified the code above like the following to retrieve the tenant_id from the context in the resolution structure:

mutation do
    field :create_rule, non_null(:rule) do
      arg(:rule, non_null(:create_rule_input))

      resolve(&RuleResolver.create_rule/3)
      middleware(SubscriptionTriggerContextMiddleware)
    end
end
subscription do
    field :rule, :rule do
      config(fn 
      _args, %{context: %{current_tenant: %{id: tenant_id}}} ->
        {:ok, topic: tenant_id}
      _, _ ->
        ErrorResolver.resolve(:forbidden)
    end)

      trigger(:create_rule,
        topic: fn %{context: %{current_tenant: %{id: tenant_id}}} ->
          tenant_id
        end
      )
    end
end

With the help of a middleware, I’m adding the resolution context to the result value of my mutation, which allows me in the end to retrieve my id:

  @behaviour Absinthe.Middleware

  def call(resolution, _config) do
    case resolution do
      %{context: context, value: resolver_result} when is_map(resolver_result) ->
        new_value = Map.put(resolver_result, :context, context)
        Map.put(resolution, :value, new_value)

      _ ->
        resolution
    end
  end

This solution is not really elegant since i’m modifying the return value of my resolver, and it also only works for resolvers results values which are structures.

Does anyone faced this problem before ?
I’m really not happy with my solution, and I’m open to any advise to improve it, or a better solution to solve my problem.

Can’t wait to have your thoughts on this !

Most Liked

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

This is a good question. Definitely the way you have it now is an option, but I think Absinthe would be better if we took a 2 arity function to trigger. There is a thing you could do with middleware too in the meantime, but I’ll need to loop back to that tomorrow.

michaelcaterisano

michaelcaterisano

@benwilson512 I’m running into the same issue; it would be great to have a 2-arity trigger callback, the second argument of which would be the resolution object for the subscription field. Do you have a suggestion for how to get around this with middleware? Specifically, I’m trying to access the subscription field name to which the trigger callback corresponds.

Where Next?

Popular in Discussions Top

arcanemachine
https://nitter.net/josevalim/status/1744395345872683471 https://twitter.com/josevalim/status/1744395345872683471
New
mikl
I wanted to capitalize a string, and tried using String.capitalize(). That generally works well, until you try to capitalize a word like...
New
laiboonh
Hi all, I am trying to convince my team to use liveview over the current react. What are some of the points where one should consider us...
New
pillaiindu
In django there is a cache framework backed by memcached. Rails also puts a lot of emphasis on caching, and even the idea of russian-doll...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
AlexMcConnell
The reason that Rails is as popular as it is is because it’s very easy for relatively inexperienced developers to get a lot of work done....
588 19652 166
New
ejpcmac
I have discovered Nix last month and I am currently on my way to migrating to it—both on macOS at home and the full NixOS distrubution at...
New
restack_oslo
Hello, Please pardon me for any faux paux. I am 46 and this is my first time on a forum of any kind. I wanted to to get answers from tho...
New
100phlecs
Are there any downsides, like perf issues, to putting all functional components in CoreComponents as long as you prefix it with the conte...
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New

Other popular topics Top

gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 31013 112
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
pmjoe
I have a relationship of love and hate with Elixir. Lots of things are just absolutely right, but there are some things that are kind of ...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
saif
Hello everyone, Long time lurker first time poster here. I’ve recently begun working on Elixir full-time again! :raised_hands: It’s been...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
jaysoifer
Is there a way to rollback a specific migration and only that one (“skipping” all the other ones)? Would mix ecto.rollback -v 200809061...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement