# `DoubleDown.ContractFacade`
[🔗](https://github.com/mccraigmccraig/double_down/blob/main/lib/double_down/contract_facade.ex#L1)

Generates a dispatch facade for a `DoubleDown.Contract`.

`use DoubleDown.ContractFacade` reads a contract's `__callbacks__/0` metadata
and generates facade functions and key helpers that
dispatch via `DoubleDown.Contract.Dispatch`.

## Combined contract + facade (simplest)

When `:contract` is omitted, it defaults to `__MODULE__` and
`use DoubleDown.Contract` is issued implicitly. This gives a single-module
contract + facade:

    defmodule MyApp.Todos do
      use DoubleDown.ContractFacade, otp_app: :my_app

      defcallback get_todo(id :: String.t()) :: {:ok, Todo.t()} | {:error, term()}
      defcallback list_todos() :: [Todo.t()]
    end

`MyApp.Todos` is both the contract (has `@callback`s, `__callbacks__/0`)
and the dispatch facade.

## Separate contract and facade

For cases where you want the contract in a different module:

    defmodule MyApp.Todos do
      use DoubleDown.ContractFacade, contract: MyApp.Todos.Contract, otp_app: :my_app
    end

## Options

  * `:contract` — the contract module that defines port operations via
    `use DoubleDown.Contract` and `defcallback` declarations. Defaults to
    `__MODULE__` (combined contract + facade).
  * `:otp_app` (required) — the OTP application name for config-based dispatch.
    Implementations are resolved from `Application.get_env(otp_app, contract)[:impl]`.
  * `:test_dispatch?` — controls whether the generated facade includes the
    `NimbleOwnership`-based test handler resolution step. Accepts `true`,
    `false`, or a zero-arity function returning a boolean. The function is
    evaluated at compile time. Defaults to `fn -> Mix.env() != :prod end`,
    so production builds get a config-only dispatch path with zero
    `NimbleOwnership` overhead.
  * `:static_dispatch?` — when `true` and `:test_dispatch?` is `false`,
    reads the implementation module from config at compile time via
    `Application.compile_env/3` and generates direct function calls —
    eliminating the `Application.get_env` lookup at runtime entirely.
    Falls back to runtime config dispatch if the config is not available
    at compile time. Accepts `true`, `false`, or a zero-arity function.
    Defaults to `fn -> Mix.env() == :prod end`.

## See also

  * `DoubleDown.BehaviourFacade` — generates dispatch facades for vanilla
    `@behaviour` modules (when you don't control the contract definition).
  * `DoubleDown.DynamicFacade` — Mimic-style bytecode interception for any module.

## Configuration

    # config/config.exs
    config :my_app, MyApp.Todos, impl: MyApp.Todos.Ecto

## Testing

    # test/test_helper.exs
    DoubleDown.Testing.start()

    # test/my_test.exs
    setup do
      DoubleDown.Testing.set_fn_handler(MyApp.Todos, fn
        :get_todo, [id] -> {:ok, %Todo{id: id}}
        :list_todos, [] -> []
      end)
      :ok
    end

    test "gets a todo" do
      assert {:ok, %Todo{}} = MyApp.Todos.get_todo("42")
    end

---

*Consult [api-reference.md](api-reference.md) for complete listing*
