# `Ash.Resource.Validation`
[🔗](https://github.com/ash-project/ash/blob/v3.23.1/lib/ash/resource/validation.ex#L5)

Represents a validation in Ash.

See `Ash.Resource.Validation.Builtins` for a list of builtin validations.

To write your own validation, define a module that implements the `c:init/1` callback
to validate options at compile time, and `c:validate/3` callback to do the validation.

Then, in a resource, you can say:

```
validations do
  validate {MyValidation, [foo: :bar]}
end
```

# `path`

```elixir
@type path() :: [atom() | integer()]
```

# `ref`

```elixir
@type ref() :: {module(), Keyword.t()} | module()
```

# `t`

```elixir
@type t() :: %Ash.Resource.Validation{
  __spark_metadata__: Spark.Dsl.Entity.spark_meta(),
  always_atomic?: term(),
  before_action?: term(),
  description: String.t() | nil,
  message: term(),
  module: atom(),
  on: [atom()],
  only_when_valid?: boolean(),
  opts: [atom()],
  validation: {atom(), [atom()]},
  where: [{atom(), [atom()]}]
}
```

# `atomic`
*optional* 

```elixir
@callback atomic(
  changeset_query_or_input :: Ash.Changeset.t() | Ash.ActionInput.t(),
  opts :: Keyword.t(),
  context :: Ash.Resource.Validation.Context.t()
) ::
  :ok
  | {:atomic, involved_fields :: [atom()] | :*, condition_expr :: Ash.Expr.t(),
     error_expr :: Ash.Expr.t()}
  | [
      {:atomic, involved_fields :: [atom()] | :*,
       condition_expr :: Ash.Expr.t(), error_expr :: Ash.Expr.t()}
    ]
  | {:not_atomic, String.t()}
  | {:error, term()}
```

# `atomic?`

```elixir
@callback atomic?() :: boolean()
```

# `batch_callbacks?`

```elixir
@callback batch_callbacks?(
  changesets_or_query :: [Ash.Changeset.t()] | Ash.Query.t(),
  opts :: Keyword.t(),
  context :: Ash.Resource.Validation.Context.t()
) :: boolean()
```

Whether or not batch callbacks should be run (if they are defined). Defaults to `true`.

# `batch_validate`
*optional* 

```elixir
@callback batch_validate(
  changesets :: [Ash.Changeset.t()],
  opts :: Keyword.t(),
  context :: Ash.Resource.Validation.Context.t()
) :: Enumerable.t(Ash.Changeset.t())
```

Replaces `validate/3` for batch actions, allowing to optimize validations for bulk actions.

Receives all changesets in the batch and returns them with errors added to any that
fail validation. Unlike `validate/3` which returns `:ok | {:error, term}`, this callback
returns the changesets directly (with errors already added via `Ash.Changeset.add_error/2`).

# `describe`
*optional* 

```elixir
@callback describe(opts :: Keyword.t()) ::
  String.t() | [message: String.t(), vars: Keyword.t()]
```

# `has_batch_validate?`

```elixir
@callback has_batch_validate?() :: boolean()
```

# `has_validate?`

```elixir
@callback has_validate?() :: boolean()
```

# `init`

```elixir
@callback init(opts :: Keyword.t()) :: {:ok, Keyword.t()} | {:error, String.t()}
```

# `supports`

```elixir
@callback supports(opts :: Keyword.t()) :: [Ash.Changeset | Ash.Query | Ash.ActionInput]
```

# `validate`
*optional* 

```elixir
@callback validate(
  changeset_query_or_input :: Ash.Changeset.t() | Ash.ActionInput.t(),
  opts :: Keyword.t(),
  context :: Ash.Resource.Validation.Context.t()
) :: :ok | {:error, term()}
```

# `action_schema`

# `opt_schema`

# `validation_type`

---

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