documentation/topics/resources/domains.md

# Domains

Domains serve three primary purposes:

1. They group related resources together, providing organization and structure to your project.
2. They allow you to define a centralized [code interface](/documentation/topics/resources/code-interfaces.md)
3. They allow you to configure certain cross-cutting concerns of those resources in a single place.

If you are familiar with a [Phoenix Context](https://hexdocs.pm/phoenix/contexts.html), you can think of a domain as the Ash equivalent.

## Grouping Resources

In an `Ash.Domain`, you will typically see something like this:

```elixir
defmodule MyApp.Tweets do
  use Ash.Domain

  resources do
    resource MyApp.Tweets.Tweet
    resource MyApp.Tweets.Comment
  end
end
```

With this definition, you can do things like placing all of these resources into a GraphQL Api with AshGraphql. You'd see a line like this:

```elixir
use AshGraphql, domains: [MyApp.Tweets]
```

## Centralized [Code Interface](/documentation/topics/resources/code-interfaces.md)

Working with our domain & resources in code *can* be done the long form way, by building changesets/queries/action inputs and calling the relevant function in `Ash`. However, we generally want to expose a well defined code API for working with our resources. This makes our code much clearer, and gives us nice things like auto complete and inline documentation.

```elixir
defmodule MyApp.Tweets do
  use Ash.Domain

  resources do
    resource MyApp.Tweets.Tweet do
      # define a function called `tweet` that uses
      # the `:create` action on MyApp.Tweets.Tweet
      define :tweet, action: :create, args: [:text]
    end

    resource MyApp.Tweets.Comment do
      # define a function called `comment` that uses
      # the `:create` action on MyApp.Tweets.Comment
      define :comment, action: :create, args: [:tweet_id, :text]
    end
  end
end
```

With these definitions, we can now do things like this:

```elixir
tweet = MyApp.Tweets.tweet!("My first tweet!", actor: user1)
comment = MyApp.Tweets.comment!(tweet.id, "What a cool tweet!", actor: user2)
```

## Configuring Cross-cutting Concerns

### Built in configuration

`Ash.Domain` comes with a number of built-in configuration options. See `d:Ash.Domain` for more.

For example:

```elixir
defmodule MyApp.Tweets do
  use Ash.Domain

  resources do
    resource MyApp.Tweets.Tweet
    resource MyApp.Tweets.Comment
  end

  execution do
    # raise the default timeout for all actions in this domain from 30s to 60s
    timeout :timer.seconds(60)
  end

  authorization do
    # disable using the authorize?: false flag when calling actions
    authorize :always
  end
end
```

### Extensions

Extensions will often come with "domain extensions" to allow you to configure the behavior of all resources within a domain, as it pertains to that extension. For example:

```elixir
defmodule MyApp.Tweets do
  use Ash.Domain,
    extensions: [AshGraphql.Domain]

  graphql do
    # skip authorization for these resources
    authorize? false
  end

  resources do
    resource MyApp.Tweets.Tweet
    resource MyApp.Tweets.Comment
  end
end
```

### Policies

You can also use `Ash.Policy.Authorizer` on your domains. This allows you to add policies that apply to *all* actions using this domain. For example:

```elixir
defmodule MyApp.Tweets do
  use Ash.Domain,
    extensions: [Ash.Policy.Authorizer]

  resources do
    resource MyApp.Tweets.Tweet
    resource MyApp.Tweets.Comment
  end

  policies do
    # add a bypass up front to allow administrators to do whatever they want
    bypass actor_attribute_equals(:is_admin, true) do
      authorize_if always()
    end

    # forbid all access from disabled users
    policy actor_attribute_equals(:disabled, true) do
      forbid_if always()
    end
  end
end
```