Part 6 · 1 chapters · ~8 min

Phoenix End to End

Generating a Phoenix app, the endpoint and plugs, the router and pipelines, controllers and JSON views, contexts as domain boundaries, Ecto schemas, changesets, queries, migrations and Ecto.Multi, authentication (phx.gen.auth), Channels, PubSub, and building the transfers API.

7

A transfers endpoint

code
mix phx.new ledger --no-html --no-assets && cd ledger && mix ecto.create

# router.ex
scope "/v1", LedgerWeb do
  pipe_through [:api, :require_api_key]
  post "/transfers", TransferController, :create
end

# transfer_controller.ex: thin
def create(conn, params) do
  key = get_req_header(conn, "idempotency-key") |> List.first()
  with {:ok, transfer} <- Ledger.create_transfer(params, key) do
    conn |> put_status(:created) |> json(%{id: transfer.id, state: transfer.state})
  end
end

# ledger.ex: the context, one transaction for the whole operation
def create_transfer(params, key) do
  Ecto.Multi.new()
  |> Ecto.Multi.insert(:idem, IdempotencyKey.changeset(%{key: key}), on_conflict: :nothing, conflict_target: :key)
  |> Ecto.Multi.run(:transfer, fn repo, %{idem: idem} -> maybe_create(repo, idem, params) end)
  |> Repo.transaction()
end
A PHOENIX REQUEST
endpoint, router, pipeline, controller, context, Ecto
Endpointplugs: parsers, session, telemetryRouterpipelines :api, :browserController / LiveViewContextLedger.create_transfer/2EctoRepo, changesets, Multi
swipe the figure sideways, or tap expand for full screen
1/4
plugs
A request flows through a pipeline of plugs (composable functions on a connection): parsing, sessions, auth, telemetry.
everything is a plugPlug.Conn