# Getting Started

## Goals

In this guide we will:

1. Create a new Elixir application and add Ash as a dependency
2. Create a simple set of resources and show they can be used
3. Illustrate some core concepts of Ash
4. Point you to good next resources so you can explore Ash further

## Things you may want to read first

- [Install Elixir](https://elixir-lang.org/install.html)
- {{ash:guide:Philosophy}}

## Requirements

If you want to follow along yourself, you will need the following things:

1. Elixir and Erlang installed 
2. A text editor to make the changes that we make
3. A terminal to run the commands we show using `iex`

## Steps

For this tutorial, we'll use examples based around creating a help desk.

We will make the following resources:

- `Helpdesk.Tickets.Ticket`
- `Helpdesk.Tickets.Representative`
- `Helpdesk.Tickets.Customer`
- `Helpdesk.Tickets.Comment`

The actions we will be able to take on these resources include:

- Opening a new ticket
- Closing a ticket
- Assigning a ticket to a representative
- Commenting on a ticket

### Create a new project

We first create a new project with the `--sup` flag to add a supervision tree. This will be necessary for later steps.

```bash
# In your terminal
mix new --sup helpdesk && cd helpdesk
```

It is a good idea to make it a git repository and commit the initial project. You'll be able to see what changes we made, and can save your changes once we're done.

```bash
# Run in your terminal
git init
git add -A
git commit -m "init"
```

Open the project in your text editor, and we'll get started.

### Add Ash to your application

Add the ash dependency to your `mix.exs`

{{mix_dep:ash}}

Add ash to your .formatter.exs file

```elixir
[
  # import the formatter rules from ash
  import_deps: [:ash],
  inputs: [...]
]
```

And run `mix deps.get`

### Creating our first resources

The basic building blocks of an Ash application are resources. They are tied together by an API module (not to be confused with a web API), which will allow you to interact with those resources.

Lets start by creating our first resource along with our first API. We will create the following files:

- The API - `lib/helpdesk/tickets.ex`
- A registry to list our resources - `lib/helpdesk/tickets/registry.ex`
- Our tickets resource - `lib/helpdesk/tickets/resources/ticket.ex`.

We also create an accompanying registry, in , which is where we will list the resources for our Api.

To create the required folders and files, you can use the following command:

```bash
# Run in your terminal
touch lib/helpdesk/tickets.ex
mkdir -p lib/helpdesk/tickets/resources && touch $_/ticket.ex
touch lib/**helpdesk**/tickets/registry.ex
```

Add the following to the files we created

```elixir
# lib/helpdesk/tickets/resources/ticket.ex

defmodule Helpdesk.Tickets.Ticket do
  # This turns this module into a resource
  use Ash.Resource

  actions do
    # Add a set of simple actions. You'll customize these later.
    defaults [:create, :read, :update, :destroy]
  end

  # Attributes are the simple pieces of data that exist on your resource
  attributes do
    # Add an autogenerated UUID primary key called `:id`.
    uuid_primary_key :id

    # Add a string type attribute called `:subject`
    attribute :subject, :string
  end
end
```

```elixir
# lib/helpdesk/tickets/registry.ex

defmodule Helpdesk.Tickets.Registry do
  use Ash.Registry,
    extensions: [
      # This extension adds helpful compile time validations
      Ash.Registry.ResourceValidations
    ]

  entries do
    entry Helpdesk.Tickets.Ticket
  end
end
```

```elixir
# lib/helpdesk/tickets.ex

defmodule Helpdesk.Tickets do
  use Ash.Api

  resources do
    # This defines the set of resources that can be used with this API
    registry Helpdesk.Tickets.Registry
  end
end
```

### Try our first resource out

Run `iex -S mix` in your project and try it out

To create a ticket, we first make an `Ash.Changeset` for the `:create` action of the `Helpdesk.Tickets.Ticket` resource. Then we pass it to the `create!/1` function on our API module `Helpdesk.Tickets`.

```elixir
Helpdesk.Tickets.Ticket
|> Ash.Changeset.for_create(:create)
|> Helpdesk.Tickets.create!()
```

This returns what we call a `record` which is an instance of a resource.

```elixir
{:ok, #Helpdesk.Tickets.Ticket<
  ...,
  id: "c0f8dc32-a018-4eb4-8656-d5810118f4ea",
  subject: nil,
  ...
>}
```

In this form, there is no persistence happening. All that this simple resource does is return the record back to us. You can see this lack of persistence by attempting to use a `read` action:

```elixir
Helpdesk.Tickets.read(Helpdesk.Tickets.Ticket)
```

Which will result in nothing being returned.

```elixir
{:ok, []}
```

Later on, we will discuss adding a {{ash:guide:Data Layers:Data Layer}} to your resources to achieve persistence. For now, however, we will focus on prototyping our resources and what we can add to them.

### Customizing our Actions

One thing you may have noticed earlier is that we created a ticket without providing any input, and as a result our ticket had a `subject` of `nil`. Additionally, we don't have any other data on the ticket. Lets add a `status` attribute, ensure that `subject` can't be `nil`, and provide a better interface by making a custom action for opening a ticket, called `:open`.


We'll start with the attribute changes:

```elixir
attributes do
  ...
  attribute :subject, :string do
    # Don't allow `nil` values
    allow_nil? false
  end

  # status is either `open` or `closed`. We can add more statuses later
  attribute :status, :atom do
    # Constraints allow you to provide extra rules for the value.
    # The available constraints depend on the type
    # See the documentation for each type to know what constraints are available
    # Since atoms are generally only used when we know all of the values
    # it provides a `one_of` constraint, that only allows those values
    constraints [one_of: [:open, :closed]]

    # The status defaulting to open makes sense
    default :open

    # We also don't want status to ever be `nil`
    allow_nil? false
  end
end
```

And then add our customized action:

```elixir
actions do
  ...
  create :open do
    # By default you can provide all public attributes to an action
    # This action should only accept the subject
    accept [:subject]
  end
end
```

Now we can play with these changes in iex:

We use `create!` with an exclamation point here because that will raise the error which gives a nicer view of the error in `iex`

```elixir
# Use this to pick up changes you've made to your code, or restart your session
recompile() 

Helpdesk.Tickets.Ticket
|> Ash.Changeset.for_create(:open, %{subject: "My mouse won't click!"})
|> Helpdesk.Tickets.create!()
```

And we can see our newly created ticket with a subject and a status.

```elixir
#Helpdesk.Tickets.Ticket<
  ...
  id: "3c94d310-7b5e-41f0-9104-5b193b831a5d",
  status: :open,
  subject: "My mouse won't click!",
  ...
>
```

If we didn't include a subject, or left out the input, we would see an error instead

```text
** (Ash.Error.Invalid) Input Invalid

* attribute subject is required
```
