AshPhoenixGenApi.Transformers.DefineFunConfigs (ash_phoenix_gen_api v1.0.3)

Copy Markdown View Source

Transformer that generates PhoenixGenApi FunConfig structs and code interface functions from Ash resource actions.

This transformer reads the gen_api DSL section configuration and:

  1. Generates PhoenixGenApi.Structs.FunConfig structs for each configured action, stored in a __ash_phoenix_gen_api_fun_configs__/0 function on the resource module.

  2. Generates code interface functions for each enabled action (when code_interface? is true), allowing developers to call Ash actions directly as Elixir functions on the resource module.

Resolution Order

For each FunConfig field, values are resolved in this order:

  1. Action-level explicit config — e.g., action :foo do timeout 10_000 end
  2. Resource section-level defaults — e.g., gen_api do timeout 5_000 end
  3. Built-in defaults — e.g., timeout defaults to 5000

For arg_types and arg_orders:

  1. Explicit arg_types/arg_orders on the action entity
  2. Auto-derived from the Ash action's accepted attributes and arguments using AshPhoenixGenApi.TypeMapper

For mfa:

  1. Explicit mfa on the action entity
  2. Auto-generated as {ResourceModule, :action_name, []}

For code_interface?:

  1. Action-level code_interface? on the action entity
  2. Section-level code_interface? — e.g., gen_api do code_interface? true end
  3. Built-in default — defaults to true

Generated Functions

After this transformer runs, the resource module will have:

def __ash_phoenix_gen_api_fun_configs__ do
  [
    %PhoenixGenApi.Structs.FunConfig{
      request_type: "send_direct_message",
      service: "chat",
      nodes: {ClusterHelper, :get_nodes, [:chat]},
      # ...
    },
    # ...
  ]
end

This function is used by AshPhoenixGenApi.Resource.Info.fun_configs/1 and by the domain-level supporter module to aggregate FunConfigs.

Additionally, for each action with code_interface? enabled, the following functions are generated. All functions use CodeInterface.params_and_opts/2 to properly disambiguate between args maps and opts keyword lists, allowing callers to pass just opts (e.g., action(actor: user)) without wrapping them in a second argument.

Create actions

def create_action(params_or_opts \\ [], opts \\ []) do
  {args, opts} = CodeInterface.params_and_opts(params_or_opts, opts)
  Changeset.for_create(__MODULE__, :create_action, args, opts)
  |> Ash.create(opts)
end

def create_action!(params_or_opts \\ [], opts \\ []) do
  {args, opts} = CodeInterface.params_and_opts(params_or_opts, opts)
  Changeset.for_create(__MODULE__, :create_action, args, opts)
  |> Ash.create!(opts)
end

Read actions

def read_action(params_or_opts \\ [], opts \\ []) do
  {args, opts} = CodeInterface.params_and_opts(params_or_opts, opts)
  Query.for_read(__MODULE__, :read_action, args, opts)
  |> Ash.read(opts)
end

def read_action!(params_or_opts \\ [], opts \\ []) do
  {args, opts} = CodeInterface.params_and_opts(params_or_opts, opts)
  Query.for_read(__MODULE__, :read_action, args, opts)
  |> Ash.read!(opts)
end

Update actions (require a record as first argument)

def update_action(record, params_or_opts \\ [], opts \\ []) do
  {args, opts} = CodeInterface.params_and_opts(params_or_opts, opts)
  Changeset.for_update(record, :update_action, args, opts)
  |> Ash.update(opts)
end

def update_action!(record, params_or_opts \\ [], opts \\ []) do
  {args, opts} = CodeInterface.params_and_opts(params_or_opts, opts)
  Changeset.for_update(record, :update_action, args, opts)
  |> Ash.update!(opts)
end

Destroy actions (require a record as first argument)

def destroy_action(record, params_or_opts \\ [], opts \\ []) do
  {args, opts} = CodeInterface.params_and_opts(params_or_opts, opts)
  Changeset.for_destroy(record, :destroy_action, args, opts)
  |> Ash.destroy(opts)
end

def destroy_action!(record, params_or_opts \\ [], opts \\ []) do
  {args, opts} = CodeInterface.params_and_opts(params_or_opts, opts)
  Changeset.for_destroy(record, :destroy_action, args, opts)
  |> Ash.destroy!(opts)
end

Generic actions

def generic_action(params_or_opts \\ [], opts \\ []) do
  {args, opts} = CodeInterface.params_and_opts(params_or_opts, opts)
  ActionInput.for_action(__MODULE__, :generic_action, args, opts)
  |> Ash.run_action(opts)
end

def generic_action!(params_or_opts \\ [], opts \\ []) do
  {args, opts} = CodeInterface.params_and_opts(params_or_opts, opts)
  ActionInput.for_action(__MODULE__, :generic_action, args, opts)
  |> Ash.run_action!(opts)
end

Summary

Functions

Runs after all other transformers so that Ash action info is fully available.

Does not need to run before any specific transformer.

Functions

after?(_)

Runs after all other transformers so that Ash action info is fully available.

after_compile?()

Callback implementation for Spark.Dsl.Transformer.after_compile?/0.

before?(_)

Does not need to run before any specific transformer.