enabling multi tenant for graphql

turning on graphql for first time in my app (multi tenant)
# router.ex
import AshAuthentication.Plug.Helpers

pipeline :graphql do
plug :load_from_bearer
plug AshGraphql.Plug
end
# router.ex
import AshAuthentication.Plug.Helpers

pipeline :graphql do
plug :load_from_bearer
plug AshGraphql.Plug
end
and my first query blows up with: Queries against the App.Elevate.Group resource require a tenant to be specified which makes sense. So reading ash graphl docs:
AshGraphql.Plug

Automatically set up the GraphQL actor and tenant.

Adding this plug to your pipeline will automatically set the actor and tenant if they were previously put there by Ash.PlugHelpers.set_actor/2 or Ash.PlugHelpers.set_tenant/2.
AshGraphql.Plug

Automatically set up the GraphQL actor and tenant.

Adding this plug to your pipeline will automatically set the actor and tenant if they were previously put there by Ash.PlugHelpers.set_actor/2 or Ash.PlugHelpers.set_tenant/2.
Adding import Ash.PlugHelpers to bring in set_tenant and the IDE complains that set_actor is ambiguous. Does it matter which set_actor is used?
7 Replies
barnabasj
barnabasj5d ago
you need another plug that get's the tenant from the somewhere and calls Ash.PlugHelpers.set_tenant(conn, tenant) just importing Ash.PlugHelpers in your router won't do that
barnabasj
barnabasj5d ago
def get_tenant(%{private: %{ash: %{tenant: tenant}}}), do: tenant That's pretty much all that function is doing IIRC there is a Plug that picks it from the subdomain somewhere, searching for it atm
Failz
FailzOP5d ago
sorry I linked the wrong function https://hexdocs.pm/ash/3.5.9/Ash.PlugHelpers.html#set_tenant/2 I was importing Ash.PlugHelpers to set the tenant, so plug AshGraphql.Plug would then get the tenant but that's where the original question came in about does it matter which set_actor is used since import AshAuthentication.Plug.Helpers and import Ash.PlugHelpers both have set_actor
barnabasj
barnabasj5d ago
They do different things, the AshAuthentication one, looks for the user that it sets on the conn and put's it as the actor at the location in the conn, other Ash extensions expect it to be. And the Ash one just straight up puts the 2nd argument as the actor into the specific location in the conn Found it https://hexdocs.pm/ash_phoenix/AshPhoenix.SubdomainPlug.html You probably want something along those lines you don't necessarily need to get the tenant from the subdomain, you could use a header or if a user can only have one tenant use that one This one just assings it under conn.assings[opts[:assign]] but you would also need to call Ash.PlugHelpers.set_tenant in that plug to make sure AshGraphql picks it up
Failz
FailzOP5d ago
I'm an idiot in the highest sense. None of my crap was working because my header name that contained the token was Bearer helps if you get the right header name Authorization 🤦‍♂️ thank you for the quick responses To help my understanding of the differences between set_tenant I need to write my own plug that leverages Ash.PlugHelpers.set_tenant; something to this effect:
defp set_tenant_from_user(conn, _opts) do
case conn.assigns[:current_user] do
%{organization_id: organization_id} when not is_nil(organization_id) ->
Ash.PlugHelpers.set_tenant(conn, organization_id)

_ ->
conn
end
end
defp set_tenant_from_user(conn, _opts) do
case conn.assigns[:current_user] do
%{organization_id: organization_id} when not is_nil(organization_id) ->
Ash.PlugHelpers.set_tenant(conn, organization_id)

_ ->
conn
end
end
And then plug AshGraphql.Plug will take the tenant that I've set in my custom plug and place it in the appropriate place when the resource action/code_interface is called?
barnabasj
barnabasj5d ago
yes, exactly

Did you find this page helpful?