Hi @benwilson512
I’m trying to resolve the type of a union that looks like this:
union(:entity_event_payload) do
types([:create_entity_payload, :delete_entity_payload])
resolve_type(fn object, resolution ->
# Here I want to derive the __typename of the resolved object and return it.
end)
end
object create_entity_payload do
field(:entity, :entity)
end
object delete_entity_payload do
field(:entity, :entity)
end
Most examples I’ve seen derive the type of the resolved object by pattern matching on it, but in my case create_entity_payload
and delete_entity_payload
are structurally identical, so I can’t do that.
Is there a way I can determine the typename of the resolved object using the resolution struct somehow?
Hey @michaelcaterisano you need to do something internally to indicate what kind of thing it is. object
is an arbitrary Elixir value that you control. You’ll need to do something to it so that your resolve_type function has something to rely on.
@benwilson512 Gotcha. The typename gets attached to the payload eventually though, right? Meaning it’s a queryable field from the client perspective:
subscription EntityEvents {
entity {
... on CreateEntityPayload {
__typename
}
}
}
Where does this information get added in the resolution process? Is it possible to access it programmatically?
You’ve got the cart before the horse a bit here. The client is fetching an entity, and doesn’t know if a given entity will be one type or another. Once Absinthe has an object with a known type, we then run __typename
on the object’s type and get a string. But it’s up to you to GIVE absinthe the type for an object, it can’t magically infer it.
@benwilson512 Gotcha. I may not understand how subscription triggers work then. I have a subscription field, entity
, which is triggered by two mutation fields, create_entity
and delete_entity
, which return a create_entity_payload
or delete_entity_payload
. What I think happens is that when the create_entity
mutation field is resolved, an entity
subscription event is triggered. If that’s true, it seems like the __typename
would be known, because the create_entity
field knows that it returns a create_entity_payload
.
Is it not the case that the resolve_type
function is called with the object returned by the create_entity
resolver after the field is finished resolving? It seems like we’re saying that resolve_type
receives the result of the create_entity
resolver, but before any type information is attached, i.e. after resolver execution, but before field resolution is complete.
Ahhhh, I see now. So you have:
mutation do
field :create_entity, :create_entity_payload
field :update_entity, :update_entity_payload
end
subscription do
field :entity, :entity_event_payload do
# has triggers for both mutation fields.
end
end
So what you’re saying is that when the entity
subscription field has been triggered by the :create_entity
mutation, that mutation has a concrete type, and so in theory that type information should be enough to clarify what the concrete type is for the subscription resolver return.
The issue is this: just that a subscription field was triggered by a mutation does not mean that the return type of the subscription has anything to do with the return type of the mutation. You can have:
subscription do
field :entity, :string do
trigger :create_entity, ...
resolve fn entity, _, _ ->
{:ok, "we did it!"}
end
end
end
By default subscription fields pass through the root object given to them by the mutation, but thats just a matter of being a convenient default, there is no essential relationship between those types at all. Moreover you wouldn’t have that info at all if a manual Absinthe.Subscription.publish
call were to happen.
Basically, the value you are publishing to the subscription has to stand on its own in terms of describing what it is.
@benwilson512 Right, I understand that the subscription resolver can return any type and is not inherently related to its triggers. What I mean is that here in your example:
subscription do
field :entity, :string do
trigger :create_entity, ...
resolve fn entity, resolution ->
# Here it seems like the resolution struct could know that `entity`
# is of the type returned by `create_entity`, i.e. `create_entity_payload`
{:ok, "we did it!"}
end
end
end
The entity
object was returned by a resolver, say create_entity
. The resolution
struct knows that this field has been resolved and now carries this value on the value
property. I’d expect the type of the object(s) in the value
property to be accessible somewhere on the resolution object since the create_entity
field has finished resolving and its return type is known.
But the resolution of the mutation, and the resolution of the subscription have nothing to do with each other. They do not share resolution objects at all. In fact this would be very dangerous as the documents might belong to completely different users!
At the end of the day, all that trigger
does is set up an automatic call that looks like this:
Absinthe.Subscription.publish(your_endpoint, value_from_resolver, entity: topic)
The only information given to the subscription documents from the mutation document is the value_from_resolver
, that’s it.