Banzai

CIHex.pmDocs

A pipeline library for Elixir providing a token-based pattern for sequential function execution with automatic error handling.

Why "Banzai"? The name comes from the Banzai Pipeline, the legendary surf reef break on the North Shore of Oahu, Hawaii — one of the most famous wave pipelines in the world.

Banzai implements a workflow pattern where a token (a map or struct) is passed through a series of steps (functions) that transform it. Each step receives the token, performs its operation, and returns an updated token. If any step fails, execution stops immediately and the error is returned.

Installation

Add banzai to your list of dependencies in mix.exs:

def deps do
  [
    {:banzai, "~> 0.1.0"}
  ]
end

Quick Start

defmodule CalculateTotal do
  use Banzai

  embedded_schema do
    field :value, :integer
  end

  def perform(params) do
    %__MODULE__{}
    |> new(params)
    |> step(fn token -> {:ok, Map.put(token, :value, token.value + 10)} end)
    |> step(fn token -> {:ok, Map.put(token, :value, token.value * 2)} end)
    |> step(fn token -> {:ok, Map.put(token, :value, token.value + 5)} end)
    |> run()
  end
end

CalculateTotal.perform(%{})
# => {:ok, %{value: 25}}

How It Works

  1. Create a token (map or struct) that holds your pipeline state
  2. Add steps that transform the token — each returns {:ok, updated_token} or {:error, reason}
  3. Run the pipeline — steps execute in order, stopping at the first error
defmodule ProcessOrder do
  use Banzai

  embedded_schema do
  field :order_id, :string

  # internal token fields
  field :total, :integer
  field :charged, :boolean

  embeds_one :order, Order

  end

  def perform(params) do
    %__MODULE__{}
    |> new(params)
    |> step(&fetch_order/1)
    |> step(&calculate_total/1)
    |> step(&charge_customer/1)
    |> run()
  end

  defp fetch_order(%__MODULE__{} = token) do
    case Orders.get(token.order_id) do
      nil -> {:error, :order_not_found}
      order -> {:ok, %__MODULE__{token | order: order}}
    end
  end

  defp calculate_total(%__MODULE__{} = token) do
    {:ok, %__MODULE__{token | total: Order.total(token.order)}
  end

  defp charge_customer(%__MODULE__{} = token) do
    case Billing.charge(token.order.customer_id, token.total) do
      :ok -> {:ok, %__MODULE__{token | charged: true}
      {:error, reason} -> {:error, reason}
    end
  end
end

Error Handling

When a step returns {:error, reason}:

License

MIT