# Contexts, JSON APIs and Authentication — Elixir & Phoenix

Source: https://www.geekswithgeeks.com/en/elixir-phoenix/p-contexts

> Organise business logic into contexts and secure APIs and pages.

## Designing a Phoenix application

Phoenix encourages grouping related functionality into **contexts**, public modules that form the boundary of a domain area, such as `Shop.Catalog`, `Shop.Orders` and `Shop.Accounts`. Controllers, LiveViews and jobs call context functions like `Orders.place_order(customer, cart)`, never the Repo or schemas directly, which keeps business rules in one tested place and makes later extraction easier. For **JSON APIs**, use the `:api` pipeline, render maps with `json/2` or JSON view modules, return proper status codes (`201` on creation, `422` with changeset errors) and handle failures centrally with **`action_fallback`**, a controller that turns `{:error, ...}` results into responses. **Authentication**: `mix phx.gen.auth` generates a secure, customisable email-based login system with hashed passwords (bcrypt, pbkdf2 or argon2), session tokens and confirmation flows; APIs commonly use bearer tokens via `Phoenix.Token` or libraries. Phoenix includes **CSRF protection**, secure headers and parameterised queries by default. Validate all input through changesets and authorise actions in contexts.

## A JSON controller with action_fallback

Contexts return tuples; the fallback controller renders errors.

```elixir
defmodule ShopWeb.OrderController do
  use ShopWeb, :controller
  alias Shop.Orders

  action_fallback ShopWeb.FallbackController

  def create(conn, %{"order" => order_params}) do
    customer = conn.assigns.current_customer

    with {:ok, order} <- Orders.place_order(customer, order_params) do
      conn
      |> put_status(:created)
      |> json(%{data: %{id: order.id, total_paise: order.total_paise}})
    end
  end
end

defmodule ShopWeb.FallbackController do
  use ShopWeb, :controller

  def call(conn, {:error, %Ecto.Changeset{} = changeset}) do
    errors =
      Ecto.Changeset.traverse_errors(changeset, fn {msg, opts} ->
        Enum.reduce(opts, msg, fn {key, value}, acc ->
          String.replace(acc, "%{#{key}}", to_string(value))
        end)
      end)

    conn |> put_status(422) |> json(%{errors: errors})
  end

  def call(conn, {:error, :not_found}) do
    conn |> put_status(:not_found) |> json(%{error: "not found"})
  end

  def call(conn, {:error, :out_of_stock}) do
    conn |> put_status(:conflict) |> json(%{error: "item out of stock"})
  end
end
```

## Contexts are boundaries, not folders

A context is valuable because other code goes through its public functions. If controllers start calling `Repo` directly, the boundary is lost and business rules spread across the web layer.

**Quiz:** What does action_fallback do in a Phoenix controller?

- [x] Sends non-conn return values such as {:error, ...} to a fallback controller that renders the response
- [ ] Retries the action
- [ ] Caches responses
- [ ] Disables CSRF

*Answer:* Sends non-conn return values such as {:error, ...} to a fallback controller that renders the response. It centralises error rendering for actions that return error tuples.
