Exop v0.4.6 Exop.Operation behaviour

Provides macros for an operation’s contract definition and process/1 function.

Example

defmodule SomeOperation do
  use Exop.Operation

  parameter :param1, type: :integer, required: true
  parameter :param2, type: :string, length: %{max: 3}, format: ~r/foo/

  def process(params) do
    "This is the operation's result with one of the params = " <> params[:param1]
  end
end

Summary

Macros

Authorizes an action with predefined policy (see policy macro docs). If authorization fails, any code after (below) auth check will be postponed (an error {:error, {:auth, _reason}} will be returned immediately)

Returns policy that was defined in an operation

Defines a parameter with name and opts in an operation contract. Options could include the parameter value checks and transformations (like coercion)

Defines a policy that will be used for authorizing the possibility of a user to invoke an operation.

defmodule ReadOperation do
  use Exop.Operation

Callbacks

Operation’s entry point. Takes defined contract as the single parameter. Contract itself is a Keyword.t list: [param_name: param_value]

Types

auth_result ::
  :ok |
  {:error, {:auth, :undefined_user}} |
  {:error, {:auth, :undefined_policy}} |
  {:error, {:auth, :undefined_action}} |
  {:error, {:auth, atom}}
interrupt_result :: {:interrupt, any}

Macros

authorize(user, opts \\ [])

Specs

authorize(term, any, Keyword.t | nil) :: auth_result

Authorizes an action with predefined policy (see policy macro docs). If authorization fails, any code after (below) auth check will be postponed (an error {:error, {:auth, _reason}} will be returned immediately)

current_policy()

Specs

current_policy(term) :: {Exop.Policy.t, atom}

Returns policy that was defined in an operation.

parameter(name, opts \\ [])

Specs

parameter(term, atom, Keyword.t) :: no_return

Defines a parameter with name and opts in an operation contract. Options could include the parameter value checks and transformations (like coercion).

Example

parameter :some_param, type: :map, required: true

Available checks are:

type

Checks whether a parameter’s value is of declared type.

parameter :some_param, type: :map

required

Checks the presence of a parameter in passed params collection.

parameter :some_param, required: true

default

Checks if the parameter is missed and assigns default value to it if so.

parameter :some_param, default: "default value"

numericality

Checks whether a parameter’s value is a number and passes constraints (if constraints were defined).

parameter :some_param, numericality: %{equal_to: 10, greater_than: 0,
                                       greater_than_or_equal_to: 10,
                                       less_than: 20,
                                       less_than_or_equal_to: 10}

in

Checks whether a parameter’s value is within a given list.

parameter :some_param, in: ~w(a b c)

not_in

Checks whether a parameter’s value is not within a given list.

parameter :some_param, not_in: ~w(a b c)

format

Checks wether parameter’s value matches given regex.

parameter :some_param, format: ~r/foo/

length

Checks the length of a parameter’s value.

parameter :some_param, length: %{min: 5, max: 10, is: 7, in: 5..8}

inner

Checks the inner of either Map or Keyword parameter.

parameter :some_param, type: :map, inner: %{
  a: [type: :integer, required: true],
  b: [type: :string, length: %{min: 1, max: 6}]
}

struct

Checks whether the given parameter is expected structure.

parameter :some_param, struct: %SomeStruct{}

func

Checks whether an item is valid over custom validation function.

parameter :some_param, func: &__MODULE__.your_validation/2

def your_validation(_params, param), do: !is_nil(param)

Coercion

It is possible to coerce a parameter before the contract validation, all validation checks will be invoked on coerced parameter value. Since coercion changes a parameter before any validation has been invoked, default values are resolved (with :default option) before the coercion. The flow looks like: Resolve param default value -> Coerce -> Validate coerced

parameter :some_param, default: 1, numericality: %{greater_than: 0}, coerce_with: &__MODULE__.coerce/1

def coerce(x), do: x * 2

For more information and examples check out general Exop docs.

policy(policy_module, action_name)

Specs

policy(term, Exop.Policy.t, atom) :: no_return

Defines a policy that will be used for authorizing the possibility of a user to invoke an operation.

defmodule ReadOperation do
  use Exop.Operation

  policy MyPolicy, :read

  parameter :user, required: true, struct: %User{}

  def process(_params) do
    authorize(params[:user])
    # make some reading...
  end
end

A policy itself might be:

defmodule MyPolicy do
  use Exop.Policy

  def read(_user, _opts), do: true

  def write(_user, _opts), do: false
end

Callbacks

process(arg0)

Operation’s entry point. Takes defined contract as the single parameter. Contract itself is a Keyword.t list: [param_name: param_value]