# `AshPhoenixGenApi.Resource.Info`
[🔗](https://github.com/ohhi-vn/ash_phoenix_gen_api/blob/v1.0.3/lib/ash_phoenix_gen_api/resource/info.ex#L1)

Introspection helpers for the `AshPhoenixGenApi.Resource` DSL extension.

Use this module to query the PhoenixGenApi configuration of an Ash resource
at runtime or during compilation.

## Helpers

This module also provides convenience functions:

- `action/2` - Get a specific action config by name
- `enabled_actions/1` - Get only enabled (non-disabled) action configs
- `action_request_type/2` - Get the effective request_type for an action
- `fun_configs/1` - Get the list of generated FunConfig structs
- `has_gen_api?/1` - Check if a resource has gen_api configured

# `action`

```elixir
@spec action(module(), atom()) :: AshPhoenixGenApi.Resource.ActionConfig.t() | nil
```

Gets a specific action configuration by name.

Returns `nil` if no action with the given name is configured.

## Parameters

  - `resource` - The Ash resource module
  - `action_name` - The action name atom

## Examples

    iex> AshPhoenixGenApi.Resource.Info.action(MyApp.Chat.DirectMessage, :send_direct_message)
    %AshPhoenixGenApi.Resource.ActionConfig{name: :send_direct_message, ...}

    iex> AshPhoenixGenApi.Resource.Info.action(MyApp.Chat.DirectMessage, :nonexistent)
    nil

# `action_request_type`

```elixir
@spec action_request_type(module(), atom()) :: String.t() | nil
```

Gets the effective request_type for a specific action.

Resolves the request_type by checking the action-level config first,
then falling back to the action name as a string.

## Parameters

  - `resource` - The Ash resource module
  - `action_name` - The action name atom

## Examples

    iex> AshPhoenixGenApi.Resource.Info.action_request_type(MyApp.Chat.DirectMessage, :send_direct_message)
    "send_direct_message"

    # If request_type is explicitly set to "send_msg":
    iex> AshPhoenixGenApi.Resource.Info.action_request_type(MyApp.Chat.DirectMessage, :send_message)
    "send_msg"

# `effective_check_permission`

```elixir
@spec effective_check_permission(module(), atom()) ::
  AshPhoenixGenApi.Resource.ActionConfig.permission_mode()
```

Gets the effective check_permission for a specific action, resolving all defaults.

## Parameters

  - `resource` - The Ash resource module
  - `action_name` - The action name atom

# `effective_choose_node_mode`

```elixir
@spec effective_choose_node_mode(module(), atom()) ::
  AshPhoenixGenApi.Resource.ActionConfig.choose_node_mode()
```

Gets the effective choose_node_mode for a specific action, resolving all defaults.

## Parameters

  - `resource` - The Ash resource module
  - `action_name` - The action name atom

# `effective_code_interface?`

```elixir
@spec effective_code_interface?(module(), atom()) :: boolean()
```

Gets the effective code_interface? for a specific action, resolving all defaults.

Resolves the code_interface? setting in this order:
1. Action-level `code_interface?` (if set)
2. Section-level `code_interface?` (if set)
3. Built-in default of `true`

## Parameters

  - `resource` - The Ash resource module
  - `action_name` - The action name atom

## Examples

    iex> AshPhoenixGenApi.Resource.Info.effective_code_interface?(MyApp.Chat.DirectMessage, :send_direct_message)
    true

# `effective_mfa`

```elixir
@spec effective_mfa(module(), atom()) :: {module(), atom(), [any()]} | nil
```

Gets the effective MFA for a specific action.

If the action config has an explicit `mfa`, returns that.
Otherwise, generates `{resource_module, action_name, []}`.

## Parameters

  - `resource` - The Ash resource module
  - `action_name` - The action name atom

# `effective_nodes`

```elixir
@spec effective_nodes(module(), atom()) ::
  AshPhoenixGenApi.Resource.ActionConfig.node_config()
```

Gets the effective nodes for a specific action, resolving all defaults.

## Parameters

  - `resource` - The Ash resource module
  - `action_name` - The action name atom

# `effective_permission_callback`

```elixir
@spec effective_permission_callback(module(), atom()) ::
  AshPhoenixGenApi.Resource.ActionConfig.permission_callback()
```

Gets the effective permission_callback for a specific action, resolving all defaults.

Resolves the permission_callback in this order:
1. Action-level `permission_callback` (if set)
2. Section-level `permission_callback` (if set)
3. Built-in default of `nil`

When `permission_callback` is set, it takes precedence over `check_permission`
and is stored in the FunConfig's `permission_callback` field.

## Parameters

  - `resource` - The Ash resource module
  - `action_name` - The action name atom

## Examples

    iex> AshPhoenixGenApi.Resource.Info.effective_permission_callback(MyApp.Chat.DirectMessage, :send_direct_message)
    nil

    iex> AshPhoenixGenApi.Resource.Info.effective_permission_callback(MyApp.Chat.DirectMessage, :admin_action)
    {MyApp.Permissions, :check_admin, []}

# `effective_request_info`

```elixir
@spec effective_request_info(module(), atom()) :: boolean()
```

Gets the effective request_info for a specific action, resolving all defaults.

## Parameters

  - `resource` - The Ash resource module
  - `action_name` - The action name atom

# `effective_response_type`

```elixir
@spec effective_response_type(module(), atom()) :: :sync | :async | :stream | :none
```

Gets the effective response_type for a specific action, resolving all defaults.

## Parameters

  - `resource` - The Ash resource module
  - `action_name` - The action name atom

# `effective_result_encoder`

```elixir
@spec effective_result_encoder(module(), atom()) ::
  AshPhoenixGenApi.Resource.ActionConfig.result_encoder()
```

Gets the effective result_encoder for a specific action, resolving all defaults.

Resolves the result_encoder in this order:
1. Action-level `result_encoder` (if set)
2. Section-level `result_encoder` (if set)
3. Built-in default of `:struct`

The `result_encoder` determines how the result returned from the action
MFA call is encoded before being returned to the caller:

- `:struct` — Return the Ash resource struct as-is (default)
- `:map` — Convert the Ash resource struct to a map containing only public fields
  (using `Ash.Resource.Info.public_fields/1` to filter; falls back to
  `Map.from_struct/1` for non-Ash-resource structs)
- `{Module, :function, args}` — Custom encoder MFA

## Parameters

  - `resource` - The Ash resource module
  - `action_name` - The action name atom

## Examples

    iex> AshPhoenixGenApi.Resource.Info.effective_result_encoder(MyApp.Chat.DirectMessage, :send_direct_message)
    :struct

    iex> AshPhoenixGenApi.Resource.Info.effective_result_encoder(MyApp.Chat.DirectMessage, :list_messages)
    :map

# `effective_retry`

```elixir
@spec effective_retry(module(), atom()) ::
  AshPhoenixGenApi.Resource.ActionConfig.retry_config()
```

Gets the effective retry for a specific action, resolving all defaults.

## Parameters

  - `resource` - The Ash resource module
  - `action_name` - The action name atom

# `effective_timeout`

```elixir
@spec effective_timeout(module(), atom()) :: pos_integer() | :infinity
```

Gets the effective timeout for a specific action, resolving all defaults.

Resolves the timeout in this order:
1. Action-level `timeout` (if set)
2. Section-level `timeout` (if set)
3. Built-in default of `5000`

## Parameters

  - `resource` - The Ash resource module
  - `action_name` - The action name atom

## Examples

    iex> AshPhoenixGenApi.Resource.Info.effective_timeout(MyApp.Chat.DirectMessage, :send_direct_message)
    10_000

# `effective_version`

```elixir
@spec effective_version(module(), atom()) :: String.t()
```

Gets the effective version for a specific action, resolving all defaults.

## Parameters

  - `resource` - The Ash resource module
  - `action_name` - The action name atom

# `enabled_actions`

```elixir
@spec enabled_actions(module()) :: [AshPhoenixGenApi.Resource.ActionConfig.t()]
```

Gets only enabled (non-disabled) action configurations.

Returns a list of `ActionConfig` structs where `disabled` is `false`.

## Parameters

  - `resource` - The Ash resource module

## Examples

    iex> AshPhoenixGenApi.Resource.Info.enabled_actions(MyApp.Chat.DirectMessage)
    [%AshPhoenixGenApi.Resource.ActionConfig{name: :send_direct_message, disabled: false, ...}, ...]

# `enabled_mfas`

```elixir
@spec enabled_mfas(module()) :: [AshPhoenixGenApi.Resource.MfaConfig.t()]
```

Gets only enabled (non-disabled) MFA configurations.

Returns a list of `MfaConfig` structs where `disabled` is `false`.

## Parameters

  - `resource` - The Ash resource module

## Examples

    iex> AshPhoenixGenApi.Resource.Info.enabled_mfas(MyApp.Chat.DirectMessage)
    [%AshPhoenixGenApi.Resource.MfaConfig{name: :ping, disabled: false, ...}, ...]

# `fun_config`

```elixir
@spec fun_config(module(), String.t()) :: PhoenixGenApi.Structs.FunConfig.t() | nil
```

Gets a specific FunConfig by request_type.

## Parameters

  - `resource` - The Ash resource module
  - `request_type` - The PhoenixGenApi request type string

## Examples

    iex> AshPhoenixGenApi.Resource.Info.fun_config(MyApp.Chat.DirectMessage, "send_direct_message")
    %PhoenixGenApi.Structs.FunConfig{request_type: "send_direct_message", ...}

# `fun_configs`

```elixir
@spec fun_configs(module()) :: [PhoenixGenApi.Structs.FunConfig.t()]
```

Gets the list of generated FunConfig structs for this resource.

This function returns the FunConfig structs that were generated by the
`AshPhoenixGenApi.Transformers.DefineFunConfigs` transformer during compilation.
The FunConfigs are stored in the resource module's `__ash_phoenix_gen_api_fun_configs__` function.

Returns an empty list if the resource has no gen_api configuration or
if the FunConfigs haven't been generated yet.

## Parameters

  - `resource` - The Ash resource module

## Examples

    iex> AshPhoenixGenApi.Resource.Info.fun_configs(MyApp.Chat.DirectMessage)
    [%PhoenixGenApi.Structs.FunConfig{request_type: "send_direct_message", ...}, ...]

# `gen_api`

```elixir
@spec gen_api(dsl_or_extended :: module() | map()) :: [struct()]
```

gen_api DSL entities

# `gen_api_check_permission`

```elixir
@spec gen_api_check_permission(dsl_or_extended :: module() | map()) ::
  {:ok, any()} | :error
```

Default permission check mode for all actions.

- `false` - No permission check (default)
- `:any_authenticated` - Requires a valid user_id
- `{:arg, "arg_name"}` - The specified argument must match user_id
- `{:role, ["admin"]}` - User must have one of the listed roles

# `gen_api_check_permission!`

```elixir
@spec gen_api_check_permission!(dsl_or_extended :: module() | map()) ::
  any() | no_return()
```

Default permission check mode for all actions.

- `false` - No permission check (default)
- `:any_authenticated` - Requires a valid user_id
- `{:arg, "arg_name"}` - The specified argument must match user_id
- `{:role, ["admin"]}` - User must have one of the listed roles

# `gen_api_choose_node_mode`

```elixir
@spec gen_api_choose_node_mode(dsl_or_extended :: module() | map()) ::
  {:ok, any()} | :error
```

Default node selection strategy for all actions.

- `:random` - Select a random node (default)
- `:hash` - Hash-based selection using request_type
- `{:hash, key}` - Hash-based selection using the specified argument key
- `:round_robin` - Round-robin across nodes

# `gen_api_choose_node_mode!`

```elixir
@spec gen_api_choose_node_mode!(dsl_or_extended :: module() | map()) ::
  any() | no_return()
```

Default node selection strategy for all actions.

- `:random` - Select a random node (default)
- `:hash` - Hash-based selection using request_type
- `{:hash, key}` - Hash-based selection using the specified argument key
- `:round_robin` - Round-robin across nodes

# `gen_api_code_interface?`

```elixir
@spec gen_api_code_interface?(dsl_or_extended :: module() | map()) :: boolean()
```

Whether to auto-generate code interface functions for the gen_api actions
on the resource module. When `true`, a function matching each action name
will be defined on the resource module that calls the action through the
Ash framework.

Individual actions can override this with their own `code_interface?` option.

Defaults to `true`.

# `gen_api_nodes`

```elixir
@spec gen_api_nodes(dsl_or_extended :: module() | map()) :: {:ok, any()} | :error
```

Default target nodes for all actions in this resource.

Can be:
- A list of node atoms: `[:"node1@host", :"node2@host"]`
- An MFA tuple that returns a node list at runtime: `{ClusterHelper, :get_nodes, [:chat]}`
- `:local` - Execute on the local node (default)

# `gen_api_nodes!`

```elixir
@spec gen_api_nodes!(dsl_or_extended :: module() | map()) :: any() | no_return()
```

Default target nodes for all actions in this resource.

Can be:
- A list of node atoms: `[:"node1@host", :"node2@host"]`
- An MFA tuple that returns a node list at runtime: `{ClusterHelper, :get_nodes, [:chat]}`
- `:local` - Execute on the local node (default)

# `gen_api_options`

```elixir
@spec gen_api_options(dsl_or_extended :: module() | map()) :: %{
  required(atom()) =&gt; any()
}
```

gen_api DSL options

Returns a map containing the and any configured or default values.

# `gen_api_permission_callback`

```elixir
@spec gen_api_permission_callback(dsl_or_extended :: module() | map()) ::
  {:ok, any()} | :error
```

Default permission callback MFA for all actions. When set, takes precedence
over `check_permission`.

Accepts `{Module, :function, []}` or `nil`. The callback function receives
`request_type` (string) and `args` (map) as arguments and returns `true`
(continue) or `false` (permission denied).

The callback function signature:

    @callback check_permission(request_type :: String.t(), args :: map()) :: boolean()

Example callback:

    def check_permission(request_type, args) do
      case request_type do
        "delete_user" -> args["role"] == "admin"
        "update_profile" -> args["user_id"] == args["target_user_id"]
        _ -> true
      end
    end

When both `permission_callback` and `check_permission` are set,
`permission_callback` takes precedence and is stored in the FunConfig's
`permission_callback` field.

Defaults to `nil`.

# `gen_api_permission_callback!`

```elixir
@spec gen_api_permission_callback!(dsl_or_extended :: module() | map()) ::
  any() | no_return()
```

Default permission callback MFA for all actions. When set, takes precedence
over `check_permission`.

Accepts `{Module, :function, []}` or `nil`. The callback function receives
`request_type` (string) and `args` (map) as arguments and returns `true`
(continue) or `false` (permission denied).

The callback function signature:

    @callback check_permission(request_type :: String.t(), args :: map()) :: boolean()

Example callback:

    def check_permission(request_type, args) do
      case request_type do
        "delete_user" -> args["role"] == "admin"
        "update_profile" -> args["user_id"] == args["target_user_id"]
        _ -> true
      end
    end

When both `permission_callback` and `check_permission` are set,
`permission_callback` takes precedence and is stored in the FunConfig's
`permission_callback` field.

Defaults to `nil`.

# `gen_api_request_info`

```elixir
@spec gen_api_request_info(dsl_or_extended :: module() | map()) ::
  {:ok, boolean()} | :error
```

Default for whether to pass request info (user_id, device_id, request_id)
as the last argument to the MFA function.

# `gen_api_request_info!`

```elixir
@spec gen_api_request_info!(dsl_or_extended :: module() | map()) ::
  boolean() | no_return()
```

Default for whether to pass request info (user_id, device_id, request_id)
as the last argument to the MFA function.

# `gen_api_response_type`

```elixir
@spec gen_api_response_type(dsl_or_extended :: module() | map()) ::
  {:ok, atom()} | :error
```

Default response mode for all actions.

- `:sync` - Client waits for the result
- `:async` - Client receives an ack, then the result later (default)
- `:stream` - Client receives streamed chunks
- `:none` - Fire and forget

# `gen_api_response_type!`

```elixir
@spec gen_api_response_type!(dsl_or_extended :: module() | map()) ::
  atom() | no_return()
```

Default response mode for all actions.

- `:sync` - Client waits for the result
- `:async` - Client receives an ack, then the result later (default)
- `:stream` - Client receives streamed chunks
- `:none` - Fire and forget

# `gen_api_result_encoder`

```elixir
@spec gen_api_result_encoder(dsl_or_extended :: module() | map()) ::
  {:ok, any()} | :error
```

Default result encoding mode for all actions.

Determines how the result returned from the action MFA call is encoded
before being returned to the caller.

- `:struct` — Return the Ash resource struct as-is (default)
- `:map` — Convert the Ash resource struct to a map containing only public fields
  (using `Ash.Resource.Info.public_fields/1` to filter; falls back to
  `Map.from_struct/1` for non-Ash-resource structs)
- `{Module, :function, args}` — Custom encoder MFA. The function receives
  the result as its first argument, followed by `args`, and must return
  the encoded result.

Individual actions can override this with their own `result_encoder` option.

For `:map` encoding, Ash resource structs are converted to maps containing
only their public fields (attributes, calculations, aggregates, relationships).
Lists of structs are mapped accordingly. Non-Ash-resource structs fall back
to `Map.from_struct/1`.
For custom MFA encoders, the function receives the result and must return
the encoded value.

Defaults to `:struct`.

# `gen_api_result_encoder!`

```elixir
@spec gen_api_result_encoder!(dsl_or_extended :: module() | map()) ::
  any() | no_return()
```

Default result encoding mode for all actions.

Determines how the result returned from the action MFA call is encoded
before being returned to the caller.

- `:struct` — Return the Ash resource struct as-is (default)
- `:map` — Convert the Ash resource struct to a map containing only public fields
  (using `Ash.Resource.Info.public_fields/1` to filter; falls back to
  `Map.from_struct/1` for non-Ash-resource structs)
- `{Module, :function, args}` — Custom encoder MFA. The function receives
  the result as its first argument, followed by `args`, and must return
  the encoded result.

Individual actions can override this with their own `result_encoder` option.

For `:map` encoding, Ash resource structs are converted to maps containing
only their public fields (attributes, calculations, aggregates, relationships).
Lists of structs are mapped accordingly. Non-Ash-resource structs fall back
to `Map.from_struct/1`.
For custom MFA encoders, the function receives the result and must return
the encoded value.

Defaults to `:struct`.

# `gen_api_retry`

```elixir
@spec gen_api_retry(dsl_or_extended :: module() | map()) :: {:ok, any()} | :error
```

Default retry configuration for all actions.

- `nil` - No retry (default)
- A positive number `n` - Equivalent to `{:all_nodes, n}`
- `{:same_node, n}` - Retry on the same node(s)
- `{:all_nodes, n}` - Retry across all available nodes

# `gen_api_retry!`

```elixir
@spec gen_api_retry!(dsl_or_extended :: module() | map()) :: any() | no_return()
```

Default retry configuration for all actions.

- `nil` - No retry (default)
- A positive number `n` - Equivalent to `{:all_nodes, n}`
- `{:same_node, n}` - Retry on the same node(s)
- `{:all_nodes, n}` - Retry across all available nodes

# `gen_api_service`

```elixir
@spec gen_api_service(dsl_or_extended :: module() | map()) :: {:ok, any()} | :error
```

The service name for this resource's API endpoints.
This is used by PhoenixGenApi to group and route API calls.

Accepts a string or atom.
Example: `"chat"`, `"user_service"`, `:notification`

# `gen_api_service!`

```elixir
@spec gen_api_service!(dsl_or_extended :: module() | map()) :: any() | no_return()
```

The service name for this resource's API endpoints.
This is used by PhoenixGenApi to group and route API calls.

Accepts a string or atom.
Example: `"chat"`, `"user_service"`, `:notification`

# `gen_api_timeout`

```elixir
@spec gen_api_timeout(dsl_or_extended :: module() | map()) :: {:ok, any()} | :error
```

Default timeout in milliseconds for all actions.
Individual actions can override this.

Accepts a positive integer or `:infinity`.

# `gen_api_timeout!`

```elixir
@spec gen_api_timeout!(dsl_or_extended :: module() | map()) :: any() | no_return()
```

Default timeout in milliseconds for all actions.
Individual actions can override this.

Accepts a positive integer or `:infinity`.

# `gen_api_version`

```elixir
@spec gen_api_version(dsl_or_extended :: module() | map()) ::
  {:ok, String.t()} | :error
```

Default version string for all actions.
Used for PhoenixGenApi API versioning.

# `gen_api_version!`

```elixir
@spec gen_api_version!(dsl_or_extended :: module() | map()) ::
  String.t() | no_return()
```

Default version string for all actions.
Used for PhoenixGenApi API versioning.

# `has_gen_api?`

```elixir
@spec has_gen_api?(module()) :: boolean()
```

Checks if a resource has the gen_api extension configured.

Returns `true` if the resource uses the `AshPhoenixGenApi.Resource` extension
and has a `gen_api` section configured, `false` otherwise.

## Parameters

  - `resource` - The Ash resource module

## Examples

    iex> AshPhoenixGenApi.Resource.Info.has_gen_api?(MyApp.Chat.DirectMessage)
    true

    iex> AshPhoenixGenApi.Resource.Info.has_gen_api?(MyApp.Chat.SomeOtherResource)
    false

# `mfa`

```elixir
@spec mfa(module(), atom()) :: AshPhoenixGenApi.Resource.MfaConfig.t() | nil
```

Gets a specific MFA configuration by name.

Returns `nil` if no MFA with the given name is configured.

## Parameters

  - `resource` - The Ash resource module
  - `mfa_name` - The MFA name atom

## Examples

    iex> AshPhoenixGenApi.Resource.Info.mfa(MyApp.Chat.DirectMessage, :ping)
    %AshPhoenixGenApi.Resource.MfaConfig{name: :ping, ...}

    iex> AshPhoenixGenApi.Resource.Info.mfa(MyApp.Chat.DirectMessage, :nonexistent)
    nil

# `mfas`

```elixir
@spec mfas(module()) :: [AshPhoenixGenApi.Resource.MfaConfig.t()]
```

Gets all MFA configurations from the resource.

Returns a list of `MfaConfig` structs.

## Parameters

  - `resource` - The Ash resource module

## Examples

    iex> AshPhoenixGenApi.Resource.Info.mfas(MyApp.Chat.DirectMessage)
    [%AshPhoenixGenApi.Resource.MfaConfig{name: :ping, ...}, ...]

# `request_types`

```elixir
@spec request_types(module()) :: [String.t()]
```

Gets all request_type strings for this resource's API endpoints.

## Parameters

  - `resource` - The Ash resource module

## Examples

    iex> AshPhoenixGenApi.Resource.Info.request_types(MyApp.Chat.DirectMessage)
    ["send_direct_message", "get_conversation", ...]

# `service`

```elixir
@spec service(module()) :: String.t() | atom() | nil
```

Gets the effective service name for a resource.

Returns the service name configured in the `gen_api` section, or `nil`
if the resource doesn't have gen_api configured.

## Parameters

  - `resource` - The Ash resource module

## Examples

    iex> AshPhoenixGenApi.Resource.Info.service(MyApp.Chat.DirectMessage)
    "chat"

---

*Consult [api-reference.md](api-reference.md) for complete listing*
