Elegant error handling in elixir pipelines. See Handling Errors in Elixir for a more detailed explanation
Documentation for OK is available on hexdoc
Available in Hex, the package can be installed as:
- Add ok to your list of dependencies in
mix.exs
:
```elixir
def deps do
[{:ok, "~> 1.2.1"}]
end
```
The erlang convention for functions that can fail is to return a result tuple.
A result tuple is a two-tuple tagged either as a success(:ok
) or a failure(:error
).
The OK module works with result tuples by treating them as a result monad.
{:ok, value} | {:error, reason}
This macro allows pipelining result tuples through a pipeline of functions.
The ~>>
macro is the is equivalent to bind/flat_map in other languages.
import OK, only: :macros
def get_employee_data(file, name) do
{:ok, file}
~>> File.read
~>> Poison.decode
~>> Dict.fetch(name)
end
def handle_user_data({:ok, data}), do: IO.puts("Contact at #{data["email"]}")
def handle_user_data({:error, :enoent}), do: IO.puts("File not found")
def handle_user_data({:error, {:invalid, _}}), do: IO.puts("Invalid JSON")
def handle_user_data({:error, :key_not_found}), do: IO.puts("Could not find employee")
get_employee_data("my_company/employees.json")
|> handle_user_data
For situations when the pipeline macro is not sufficiently flexible.
To extract a value for an ok tuple use the <-
operator.
OK.try do
a <- safe_div(6, 2)
b = a + 1
c <- safe_div(b, 2)
{:ok, a + c}
end
The above code is equivalent to
case safe_div(6, 2) do
{:ok, a} ->
b = a + 1
case safe_div(b, 2) do
result = {:ok, c} ->
{:ok, a + c}
{:error, reason} ->
{:error, reason}
end
{:error, reason} ->
{:error, reason}
end
OK
can be used for railway programming.
An explanation of this is available in this blog
For reference.
Possible extensions to include implementing bind on structs so that errors can be better handled. Implement a catch functionality for functions that error. Implement existing monad library protocols so can extend similar DB functionality e.g. slick