How to set values in the context from plug and access from actions

I want to set some values using Plug in ash context and want to use it on GraphQL queries.

  1. router.ex
defmodule BekrafterBackendWeb.Router do
  use BekrafterBackendWeb, :router

  pipeline :graphql do
    plug BekrafterBackend.Plug
    plug AshGraphql.Plug
  end

  scope "/" do
    pipe_through [:graphql]

    forward "/gql",
      Absinthe.Plug,
      schema: Module.concat(["BekrafterBackend.Graphql.Schema"])

    forward "/playground",
            Absinthe.Plug.GraphiQL,
            schema: Module.concat(["BekrafterBackend.Graphql.Schema"]),
            interface: :playground
  end
end

  1. Plug.ex
defmodule BekrafterBackend.Plug do
  @behaviour Plug

  def init(opts), do: opts

  def call(conn, _opts) do
    conn
    |> AshAuthentication.Plug.Helpers.retrieve_from_bearer(:bekrafterbackend)
    |> AshAuthentication.Plug.Helpers.set_actor(:user)
    |> Ash.PlugHelpers.set_context(%{test: "test"})
  end
end

  1. hello.ex
defmodule BekrafterBackend.Introduction.Hello do
  use Ash.Resource,
  domain: BekrafterBackend.Introduction,
  data_layer: Ash.DataLayer.Ets,
  extensions: [
    AshGraphql.Resource
  ],
  authorizers: [
    Ash.Policy.Authorizer
  ]

  @all_attributes [:id, :message]

  attributes do
    uuid_primary_key :id
    attribute :message, :string, allow_nil?: false, public?: true
  end

  actions do
    defaults [:read]

    create :create do
      accept @all_attributes
    end

    update :update do
      accept @all_attributes
    end

    destroy :destroy do
      accept [:id]
    end

    action :say_hello, :string do
      run fn _input, context ->
        {:ok, "Hello, #{context.test}!"}
      end
    end
  end

  code_interface do
    define :say_hello, args: []
  end

  graphql do
    type :introduction

    queries do
      get :get_message, :read
      list :list_message, :read
      action :say_hello, :say_hello
    end

    mutations do
      create :create_message, :create
      update :update_message, :update
      destroy :delete_message, :destroy
    end
  end

  policies do
    policy action(:say_hello) do
      authorize_if actor_present()
    end
  end
end

I am unable to access the test key from the say_hello action set in the context. Could you please help me with this?

It is unfortunately confusing, but there are two contexts. There is the context argument provided to function callbacks like that. It contains a specific and unchanging set of keys like actor and tenant, and then there is the action context which can contain arbitrary information.

     run fn input, context ->
        {:ok, "Hello, #{input.context.test}!"}
      end

Thank you so much. It has solved the issue. But, it seems confusing at first which one holds which information :sweat_smile:

Yes, agreed. In future versions we may update the documentation to provide a different standard name for that variable, or something along those lines.

1 Like