# Code Interfaces Use code interfaces on domains to define the contract for calling into Ash resources. See the [Code interface guide for more](https://hexdocs.pm/ash/code-interfaces.html). Define code interfaces on the domain, like this: ```elixir resource ResourceName do define :fun_name, action: :action_name end ``` For more complex interfaces with custom transformations: ```elixir define :custom_action do action :action_name args [:arg1, :arg2] custom_input :arg1, MyType do transform do to :target_field using &MyModule.transform_function/1 end end end ``` Prefer using the primary read action for "get" style code interfaces, and using `get_by` when the field you are looking up by is the primary key or has an `identity` on the resource. ```elixir resource ResourceName do define :get_thing, action: :read, get_by: [:id] end ``` **Avoid direct Ash calls in web modules** - Don't use `Ash.get!/2` and `Ash.load!/2` directly in LiveViews/Controllers, similar to avoiding `Repo.get/2` outside context modules: You can also pass additional inputs in to code interfaces before the options: ```elixir resource ResourceName do define :create, action: :action_name, args: [:field1] end ``` ```elixir Domain.create!(field1_value, %{field2: field2_value}, actor: current_user) ``` You should generally prefer using this map of extra inputs over defining optional arguments. ```elixir # BAD - in LiveView/Controller group = MyApp.Resource |> Ash.get!(id) |> Ash.load!(rel: [:nested]) # GOOD - use code interface with get_by resource DashboardGroup do define :get_dashboard_group_by_id, action: :read, get_by: [:id] end # Then call: MyApp.Domain.get_dashboard_group_by_id!(id, load: [rel: [:nested]]) ``` **Code interface options** - Prefer passing options directly to code interface functions rather than building queries manually: ```elixir # PREFERRED - Use the query option for filter, sort, limit, etc. # the query option is passed to `Ash.Query.build/2` posts = MyApp.Blog.list_posts!( query: [ filter: [status: :published], sort: [published_at: :desc], limit: 10 ], load: [author: :profile, comments: [:author]] ) # All query-related options go in the query parameter users = MyApp.Accounts.list_users!( query: [filter: [active: true], sort: [created_at: :desc]], load: [:profile] ) # AVOID - Verbose manual query building query = MyApp.Post |> Ash.Query.filter(...) |> Ash.Query.load(...) posts = Ash.read!(query) ``` Supported options: `load:`, `query:` (which accepts `filter:`, `sort:`, `limit:`, `offset:`, etc.), `page:`, `stream?:` **Using Scopes in LiveViews** - When using `Ash.Scope`, the scope will typically be assigned to `scope` in LiveViews and used like so: ```elixir # In your LiveView MyApp.Blog.create_post!("new post", scope: socket.assigns.scope) ``` Inside action hooks and callbacks, use the provided `context` parameter as your scope instead: ```elixir |> Ash.Changeset.before_transaction(fn changeset, context -> MyApp.ExternalService.reserve_inventory(changeset, scope: context) changeset end) ``` ## Authorization Functions For each action defined in a code interface, Ash automatically generates corresponding authorization check functions: - `can_action_name?(actor, params \\ %{}, opts \\ [])` - Returns `true`/`false` for authorization checks - `can_action_name(actor, params \\ %{}, opts \\ [])` - Returns `{:ok, true/false}` or `{:error, reason}` Example usage: ```elixir # Check if user can create a post if MyApp.Blog.can_create_post?(current_user) do # Show create button end # Check if user can update a specific post if MyApp.Blog.can_update_post?(current_user, post) do # Show edit button end # Check if user can destroy a specific comment if MyApp.Blog.can_destroy_comment?(current_user, comment) do # Show delete button end ``` These functions are particularly useful for conditional rendering of UI elements based on user permissions.