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

PragTob
Hello everyone, I know we had quite some threads (read through lots of them) about background job processing but it remains a hotly deba...
New
Nvim
Elixir appears to be a superior language to Python. I don’t see any advantage of Python over Elixir. Are there any?
New
mmmrrr
Just saw that dhh announced https://hotwire.dev/ Is it just me or is this essentially live view? :smiley: Although I like the “iFrame-e...
New
chuck
Let me start by stating an assumption: Phoenix is a great approach to building REST APIs. There are many reasons for this, but I will ass...
New
marciol
Please, let me know if this kind of discussion already took place in another topic . Hi all, how do you consider if is better to build ...
New
shishini
I think this twitter post and youtube video didn’t get as much attention as I hoped I am still new to Elixir, so can’t really judge ...
New
JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1144 54120 245
New
MarioFlach
Hello, I want to share a project I’ve been working on for a while: https://github.com/almightycouch/gitgud Background Some time ago I ...
New
sashaafm
Piggy backing a bit on @dvcrn topic BEAM optimization for functions with static return type?, I’ve been trying to understand in a deeper ...
New
slashdotdash
Phoenix Live View is now publicly available on GitHub. Here’s Chris McCord’s tweet announcing making it public.
New

Other popular topics Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
Fl4m3Ph03n1x
About me? ( if you have nothing better to do than reading about some random guy in the internet :stuck_out_tongue: ) Hello all, this is ...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 39467 209
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
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
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement