Current section
Files
Jump to
Current section
Files
lib/hex_port.ex
defmodule HexPort do
@moduledoc """
Hexagonal architecture ports for Elixir.
HexPort provides typed port contracts with async-safe test doubles,
dispatch logging, and stateful test handlers. Define boundaries with
`defport`, swap implementations for testing without a database.
## Defining a Contract
defmodule MyApp.Todos do
use HexPort.Contract
defport get_todo(tenant_id :: String.t(), id :: String.t()) ::
{:ok, Todo.t()} | {:error, term()}
defport list_todos(tenant_id :: String.t()) :: [Todo.t()]
end
This generates:
* `MyApp.Todos.Behaviour` — standard `@behaviour` with `@callback`s
* `MyApp.Todos.__port_operations__/0` — operation metadata
## Generating a Dispatch Facade
defmodule MyApp.Todos.Port do
use HexPort.Port, contract: MyApp.Todos, otp_app: :my_app
end
This generates facade functions, bang variants, and key helpers
that dispatch via `HexPort.Dispatch`.
## Configuration
# config/config.exs
config :my_app, MyApp.Todos, impl: MyApp.Todos.Ecto
## Testing
# test/test_helper.exs
HexPort.Testing.start()
# test/my_test.exs
setup do
HexPort.Testing.set_fn_handler(MyApp.Todos, fn
:get_todo, [_tenant, id] -> {:ok, %Todo{id: id}}
:list_todos, [_tenant] -> []
end)
:ok
end
test "gets a todo" do
assert {:ok, %Todo{}} = MyApp.Todos.Port.get_todo("t1", "todo-1")
end
"""
end