Composition and error handling of sequential computations, similar to
Ecto.Multi
Taco allows to create a chain of actions which might either succeed, fail, or halt the execution of further actions in the pipeline.
See the online documentation
In your mix.exs
:
def deps do
[
...
{:taco, "~> 0.1"}
...
]
end
and mix.deps get
.
In the Elixir world there are many solutions for composing functions which
might either fail or succeed. There is a with
special form, there are
libraries like OK which provide error
handling for the |>
operator. Taco may not be such elegant as those
solutions, however it provides a couple of features which make it unique
in the ecosystem (for now).
- Tagging
with
special form allows us to match on return values of functions, and
optionally catch the values that didn't match in the else
block:
with {:ok, user} <- authenticate(credentials),
{:ok, user} <- authorize(user, action) do
:ok
else
{:error, error} ->
handle_error(error)
end
However, if both functions return {:error, error}
on failure, there is no
way to know which one failed without wrapping the calls in a tuple:
with {:authenticate, {:ok, user}} <- {:authenticate, authenticate(credentials)},
{:authorize, {:ok, user}} <- {:authorize, authorize(user, action)} do
:ok
else
{:authenticate, {:error, error}} ->
handle_authentication_error(error)
{:authorize, {:error, error}} ->
handle_authorization_error(error)
end
This may become really verbose and (in my opinion) doesn't look clean.
Taco requires you to tag all the actions, so that when one of them fails, you know exactly which one:
Taco.new()
|> Taco.then(:authenticate, fn _ -> authenticate(user) end)
|> Taco.then(:authorize, fn %{authenticate: user} -> authorize(user) end)
|> Taco.run()
# when both succeed
{:ok, :authorize, user}
# when `:authorize` fails
{:error, :authorize, error, %{authenticate: user}}
- Laziness
There is not much to be explained here. None of the actions in the taco are
executed until Taco.run/1
is called. This allows you to pass the taco
around until you really need to get the return value.
- Haltable pipeline
Each action in the taco may return {:halt, result}
tuple. In such case
no further actions in the pipeline are executed, and Taco.run/1
returns
as if the action was the last in the pipeline ({:ok, tag, result}
).
- Taco allows to tag each action, so that you know exactly which one has failed
Taco.then/3
operates on pure data structures, actions are executed only whenTaco.run/1
is called (much likeEcto.Multi.run/3
andEcto.Repo.transaction/1
)- Each action in the pipeline has access to results of previous actions
Copyright 2017, Arkadiusz Gil
Released under MIT license.
Check LICENSE file for more information.