# Generic Actions Generic actions are so named because there are no special rules about how they work. A generic action takes arguments and returns a value. The struct used for building input for a generic action is `Ash.ActionInput`. ```elixir action :say_hello, :string do argument :name, :string, allow_nil?: false run fn input, _ -> {:ok, "Hello: #{input.arguments.name}" end end ``` A generic action declares its arguments, return type, and implementation, as illustrated above. ## Why use generic actions? The example above could be written as a normal function in elixir, i.e ```elixir def say_hello(name), do: "Hello: #{name}" ``` The benefit of using generic actions instead of defining normal functions: - They can be used with api extensions like `ash_json_api` and `ash_graphql` - Their inputs are type checked and casted - They support Ash authorization patterns (i.e policies) - They can be included in the code interface of a resource - They can be made transactional with a single option (`transaction? true`) If you don't need any of the above, then there is no problem with writing regular Elixir functions! ## Return types and constraints Generic actions do not cast their return types. It is expected that the action return a valid value for the type that they declare. However, declaring additional constraints can inform API usage, and make the action more clear. For example: ```elixir action :priority, :integer do constraints [min: 1, max: 3] argument :status, :atom, constraints: [one_of: [:high, :medium, :low]] run fn input, _ -> case input.arguments.status do :high -> {:ok, 3} :medium -> {:ok, 2} :low -> {:ok, 1} end end end ``` > #### Returning resource instances {: .tip} > > It sometimes happens that you want to make a generic action which returns an > instance or instances of the resource. It's natural to assume that you can > set your action's return type to the name of your resource. Unfortunately > this will result in a compile error as the resource struct is not yet defined > at the time of DSL transformation. The work around is to define an action > that returns `:struct` and is constrained to only be of a specific type, eg: > > ```elixir > action :get, :struct do > constraints instance_of: __MODULE__ > > run # ... > end > ```