Paraiso (paraiso v0.0.8)

The module of Paraiso

Link to this section Summary

Types

prop/3で宣言してprocess/2で処理される処理内容を表現した中間オブジェクト

validatorを表す型。prop/3の引数validatorと同じ

Functions

第一引数paramsに対して第二引数propsで宣言されたバリデーションおよびサニタイズを実行する

オブジェクトのname/valueペアに対する、require/optionalおよびバリデーション仕様を宣言する

Link to this section Types

Link to this opaque

prop()

(opaque)

Specs

prop()

prop/3で宣言してprocess/2で処理される処理内容を表現した中間オブジェクト

Specs

validator() ::
  :boolean
  | :int
  | nil
  | {:int, {:range, min :: integer(), max :: integer()}}
  | :string
  | {:string, {:range, min :: integer(), max :: integer()}}
  | {:string, {:regex, Regex.t()}}
  | String.t()
  | {:string_literals, [String.t()]}
  | {:string_as_atom, atom() | [atom()]}
  | {:object, [prop()]}
  | :object
  | {:array, validator()}
  | {:or, [validator()]}
  | {:custom,
     (value :: term() ->
        :ok
        | {:ok, any()}
        | {:error, reason :: atom()}
        | {:error, atom() | [atom() | integer()], atom()})}

validatorを表す型。prop/3の引数validatorと同じ

Link to this section Functions

Link to this function

process(params, props)

Specs

process(map(), [prop()]) ::
  {:ok, map()} | {:error, atom() | [atom() | integer()], atom()}

第一引数paramsに対して第二引数propsで宣言されたバリデーションおよびサニタイズを実行する

返り値

検証成功の場合

{:ok, <サニタイズされた値>} が返る

paramsでキーがStringの場合atomに変換される。またpropsに含まれないキーは削除される

iex> Paraiso.process(%{"a" => "abc", "b" => "cde"}, [Paraiso.prop(:a, :required, "abc")])
{:ok, %{a: "abc"}}

検証失敗の場合

{:error, <失敗箇所>, <失敗理由>} が返る

あるpropで検証失敗した場合その時点で検証処理は打ち切られる。

Link to this function

prop(name, req_or_opt, validator)

Specs

prop(
  name :: atom(),
  required_or_optional ::
    :required | {:optional, default :: term()} | :optional,
  validator ::
    :boolean
    | nil
    | :int
    | {:int, {:range, min :: integer(), max :: integer()}}
    | :string
    | {:string, {:range, min :: integer(), max :: integer()}}
    | {:string, {:regex, Regex.t()}}
    | String.t()
    | {:string_literals, [String.t()]}
    | {:string_as_atom, atom() | [atom()]}
    | {:object, [prop()]}
    | :object
    | {:array, validator()}
    | {:or, [validator()]}
    | {:custom,
       (value :: term() ->
          :ok
          | {:ok, any()}
          | {:error, reason :: atom()}
          | {:error, atom() | [atom() | integer()], atom()})}
) :: prop()

オブジェクトのname/valueペアに対する、require/optionalおよびバリデーション仕様を宣言する

引数

  • name: 宣言対象のname
  • required_or_optional: このプロパティは必須かオプションか
  • validator: バリデーション仕様

required_or_optional

:required or {:optional, default :: term()} or :optional

:required

必須属性

iex> Paraiso.process(%{"a" => 1}, [Paraiso.prop(:a, :required, :int)])
{:ok, %{a: 1}}
iex> Paraiso.process(%{"b" => 1}, [Paraiso.prop(:a, :required, :int)])
{:error, :a, :required}

{:optional, default :: term()}

オプション属性。省略されていた場合defaultが補完される

iex> Paraiso.process(%{"a" => 1}, [Paraiso.prop(:a, {:optional, 0}, :int)])
{:ok, %{a: 1}}
iex> Paraiso.process(%{"b" => 1}, [Paraiso.prop(:a, {:optional, 0}, :int)])
{:ok, %{a: 0}}

:optional

オプション属性。省略されていた場合は補完されない

iex> Paraiso.process(%{"a" => 1}, [Paraiso.prop(:a, :optional, :int)])
{:ok, %{a: 1}}
iex> Paraiso.process(%{"b" => 1}, [Paraiso.prop(:a, :optional, :int)])
{:ok, %{}}

validator

:boolean

trueまたはfalseであるか検証

iex> Paraiso.process(%{"a" => true}, [Paraiso.prop(:a, :required, :boolean)])
{:ok, %{a: true}}
iex> Paraiso.process(%{"a" => false}, [Paraiso.prop(:a, :required, :boolean)])
{:ok, %{a: false}}
iex> Paraiso.process(%{"a" => "foo"}, [Paraiso.prop(:a, :required, :boolean)])
{:error, :a, :invalid}

nil

nilであるか検証

iex> Paraiso.process(%{"a" => nil}, [Paraiso.prop(:a, :required, nil)])
{:ok, %{a: nil}}
iex> Paraiso.process(%{"a" => false}, [Paraiso.prop(:a, :required, nil)])
{:error, :a, :invalid}

:int

整数型であるか検証

iex> Paraiso.process(%{"a" => 1}, [Paraiso.prop(:a, :required, :int)])
{:ok, %{a: 1}}
iex> Paraiso.process(%{"a" => "foo"}, [Paraiso.prop(:a, :required, :int)])
{:error, :a, :invalid}

{:int, {:range, min :: integer(), max :: integer()}}

min以上max以下の整数型であるか検証

iex> Paraiso.process(%{"a" => 0}, [Paraiso.prop(:a, :required, {:int, {:range, 0, 100}})])
{:ok, %{a: 0}}
iex> Paraiso.process(%{"a" => 100}, [Paraiso.prop(:a, :required, {:int, {:range, 0, 100}})])
{:ok, %{a: 100}}
iex> Paraiso.process(%{"a" => -1}, [Paraiso.prop(:a, :required, {:int, {:range, 0, 100}})])
{:error, :a, :invalid}
iex> Paraiso.process(%{"a" => 101}, [Paraiso.prop(:a, :required, {:int, {:range, 0, 100}})])
{:error, :a, :invalid}
iex> Paraiso.process(%{"a" => "foo"}, [Paraiso.prop(:a, :required, {:int, {:range, 0, 100}})])
{:error, :a, :invalid}

:string

文字列であるか検証

iex> Paraiso.process(%{"a" => "a"}, [Paraiso.prop(:a, :required, :string)])
{:ok, %{a: "a"}}
iex> Paraiso.process(%{"a" => 123}, [Paraiso.prop(:a, :required, :string)])
{:error, :a, :invalid}

{:string, {:range, min :: integer(), max :: integer()}}

長さmin以上max以下の文字列であるか検証

iex> Paraiso.process(%{"a" => "a"}, [Paraiso.prop(:a, :required, {:string, {:range, 1, 3}})])
{:ok, %{a: "a"}}
iex> Paraiso.process(%{"a" => "abc"}, [Paraiso.prop(:a, :required, {:string, {:range, 1, 3}})])
{:ok, %{a: "abc"}}
iex> Paraiso.process(%{"a" => ""}, [Paraiso.prop(:a, :required, {:string, {:range, 1, 3}})])
{:error, :a, :invalid}
iex> Paraiso.process(%{"a" => "abcd"}, [Paraiso.prop(:a, :required, {:string, {:range, 1, 3}})])
{:error, :a, :invalid}
iex> Paraiso.process(%{"a" => 1}, [Paraiso.prop(:a, :required, {:string, {:range, 1, 3}})])
{:error, :a, :invalid}

{:string, {:regex, Regex.t()}}

正規表現にマッチする文字列であるか検証

iex> Paraiso.process(%{"a" => "abc"}, [Paraiso.prop(:a, :required, {:string, {:regex, ~r/^abc/}})])
{:ok, %{a: "abc"}}
iex> Paraiso.process(%{"a" => "def"}, [Paraiso.prop(:a, :required, {:string, {:regex, ~r/^abc/}})])
{:error, :a, :invalid}
iex> Paraiso.process(%{"a" => 1}, [Paraiso.prop(:a, :required, {:string, {:regex, ~r/^abc/}})])
{:error, :a, :invalid}

String.t()

文字列リテラルと一致するか検証

iex> Paraiso.process(%{"a" => "abc"}, [Paraiso.prop(:a, :required, "abc")])
{:ok, %{a: "abc"}}
iex> Paraiso.process(%{"a" => "def"}, [Paraiso.prop(:a, :required, "abc")])
{:error, :a, :invalid}
iex> Paraiso.process(%{"a" => 1}, [Paraiso.prop(:a, :required, "abc")])
{:error, :a, :invalid}

{:string_literals, [String.t()]}

リスト中のいずれかの文字列リテラルと一致するか検証

iex> Paraiso.process(%{"a" => "abc"}, [Paraiso.prop(:a, :required, {:string_literals, ["abc", "def"]})])
{:ok, %{a: "abc"}}
iex> Paraiso.process(%{"a" => "def"}, [Paraiso.prop(:a, :required, {:string_literals, ["abc", "def"]})])
{:ok, %{a: "def"}}
iex> Paraiso.process(%{"a" => "ghi"}, [Paraiso.prop(:a, :required, {:string_literals, ["abc", "def"]})])
{:error, :a, :invalid}
iex> Paraiso.process(%{"a" => 1}, [Paraiso.prop(:a, :required, {:string_literals, ["abc", "def"]})])
{:error, :a, :invalid}

{:string_as_atom, atom() | [atom()]}

いずれかのアトムと一致するか検証。検証に成功した場合、結果の値はアトムとして保持される

iex> Paraiso.process(%{"a" => "abc"}, [Paraiso.prop(:a, :required, {:string_as_atom, :abc})])
{:ok, %{a: :abc}}
iex> Paraiso.process(%{"a" => "def"}, [Paraiso.prop(:a, :required, {:string_as_atom, :abc})])
{:error, :a, :invalid}
iex> Paraiso.process(%{"a" => "abc"}, [Paraiso.prop(:a, :required, {:string_as_atom, [:abc, :def]})])
{:ok, %{a: :abc}}
iex> Paraiso.process(%{"a" => "def"}, [Paraiso.prop(:a, :required, {:string_as_atom, [:abc, :def]})])
{:ok, %{a: :def}}
iex> Paraiso.process(%{"a" => "ghi"}, [Paraiso.prop(:a, :required, {:string_as_atom, [:abc, :def]})])
{:error, :a, :invalid}
iex> Paraiso.process(%{"a" => 1}, [Paraiso.prop(:a, :required, {:string_as_atom, [:abc, :def]})])
{:error, :a, :invalid}

{:object, [prop()]}

対象オブジェクトをvalueとした場合にParaiso.process(value, [prop()])に相当する検証をする

検証に成功した場合: map()が値部分に格納される

検証に失敗した場合: {:error, [<エラーが発生した要素までのパス>], reason} が返る

iex> Paraiso.process(
...>   %{"a" => %{"b" => "c"}},
...>   [Paraiso.prop(:a, :required, {:object, [Paraiso.prop(:b, :required, "c")]})]
...> )
{:ok, %{a: %{b: "c"}}}
iex> Paraiso.process(
...>   %{"a" => %{"b" => "d"}},
...>   [Paraiso.prop(:a, :required, {:object, [Paraiso.prop(:b, :required, "c")]})]
...> )
{:error, [:a, :b], :invalid}
iex> Paraiso.process(
...>   %{"a" => "b"},
...>   [Paraiso.prop(:a, :required, {:object, [Paraiso.prop(:b, :required, "c")]})]
...> )
{:error, :a, :invalid}

:object

オブジェクト型であるか検証

検証に成功した場合: map()が値部分に格納される(キーはatom()に変換されない)

検証に失敗した場合: {:error, [<エラーが発生した要素までのパス>], reason} が返る

iex> Paraiso.process(
...>   %{"a" => %{"b" => "c"}},
...>   [Paraiso.prop(:a, :required, :object)]
...> )
{:ok, %{a: %{"b" => "c"}}}
iex> Paraiso.process(
...>   %{"a" => 1},
...>   [Paraiso.prop(:a, :required, :object)]
...> )
{:error, :a, :invalid}

{:array, validator()}

リスト中の要素に対してvalidator()に基づいて検証する

検証に失敗した場合、 {:error, [<エラーが発生した要素までのパス>], reason} が返る

iex> Paraiso.process(
...>   %{"a" => [1, 2, 3]},
...>   [Paraiso.prop(:a, :required, {:array, :int})]
...> )
{:ok, %{a: [1, 2, 3]}}
iex> Paraiso.process(
...>   %{"a" => ["foo", 2, 3]},
...>   [Paraiso.prop(:a, :required, {:array, :int})]
...> )
{:error, [:a, 0], :invalid}
iex> Paraiso.process(
...>   %{"a" => [%{"b" => 1}, %{"b" => "c"}]},
...>   [Paraiso.prop(:a, :required, {:array, {:object, [Paraiso.prop(:b, :required, :int)]}})]
...> )
{:error, [:a, 1, :b], :invalid}
iex> Paraiso.process(
...>   %{"a" => "foo"},
...>   [Paraiso.prop(:a, :required, {:array, {:object, [Paraiso.prop(:b, :required, :int)]}})]
...> )
{:error, :a, :invalid}

{:or, [validator()]}

リスト中のいずれかで成功するか検証する

iex> Paraiso.process(
...>   %{"a" => true},
...>   [Paraiso.prop(:a, :required, {:or, [:boolean, "foo"]})]
...> )
{:ok, %{a: true}}
iex> Paraiso.process(
...>   %{"a" => "foo"},
...>   [Paraiso.prop(:a, :required, {:or, [:boolean, "foo"]})]
...> )
{:ok, %{a: "foo"}}
iex> Paraiso.process(
...>   %{"a" => "bar"},
...>   [Paraiso.prop(:a, :required, {:or, [:boolean, "foo"]})]
...> )
{:error, :a, :invalid}
iex> Paraiso.process(
...>   %{"a" => %{"b" => "c"}},
...>   [
...>     Paraiso.prop(
...>       :a,
...>       :required,
...>       {:or,
...>        [
...>          nil,
...>          {:object,
...>           [
...>             Paraiso.prop(:b, :required, :string)
...>           ]}
...>        ]}
...>     )
...>   ]
...> )
{:ok, %{a: %{b: "c"}}}
iex> Paraiso.process(
...>   %{"a" => nil},
...>   [
...>     Paraiso.prop(
...>       :a,
...>       :required,
...>       {:or,
...>        [
...>          nil,
...>          {:object,
...>           [
...>             Paraiso.prop(:b, :required, :string)
...>           ]}
...>        ]}
...>     )
...>   ]
...> )
{:ok, %{a: nil}}

{:custom, (value :: term() -> :ok | {:error, reason :: atom()})}

関数で検証する。関数の仕様は以下

検証に成功した場合、:ok を返す。また、成功で、バリデーション済みオブジェクトを返したければ {:ok, <オブジェクト> :: any()} を返す

検証に失敗した場合、{:error, <失敗理由> :: atom()} を返す。また、失敗で、失敗したパスを返したければ {:error, <失敗したパス情報> :: atom() | [atom() | integer()], <失敗理由> :: atom()} を返す

iex> Paraiso.process(
...>   %{"a" => 1},
...>   [
...>     Paraiso.prop(
...>       :a,
...>       :required,
...>       {:custom, fn v -> if(v == 1, do: :ok, else: {:error, :invalid}) end}
...>     )
...>   ]
...> )
{:ok, %{a: 1}}
iex> Paraiso.process(
...>   %{"a" => 2},
...>   [
...>     Paraiso.prop(
...>       :a,
...>       :required,
...>       {:custom, fn v -> if(v == 1, do: :ok, else: {:error, :invalid}) end}
...>     )
...>   ]
...> )
{:error, :a, :invalid}
iex> Paraiso.process(
...>   %{"a" => %{"b" => 1}},
...>   [
...>     Paraiso.prop(
...>       :a,
...>       :required,
...>       {:custom, fn %{"b" => v} -> if(v == 1, do: {:ok, %{b: v}}, else: {:error, :b, :invalid}) end}
...>     )
...>   ]
...> )
{:ok, %{a: %{b: 1}}}
iex> Paraiso.process(
...>   %{"a" => %{"b" => 2}},
...>   [
...>     Paraiso.prop(
...>       :a,
...>       :required,
...>       {:custom, fn %{"b" => v} -> if(v == 1, do: {:ok, %{b: v}}, else: {:error, :b, :invalid}) end}
...>     )
...>   ]
...> )
{:error, [:a, :b], :invalid}
iex> Paraiso.process(
...>   %{"a" => %{"b" => %{"c" => 2}}},
...>   [
...>     Paraiso.prop(
...>       :a,
...>       :required,
...>       {:custom, fn %{"b" => %{"c" => v}} -> if(v == 1, do: {:ok, %{b: %{c: v}}}, else: {:error, [:b, :c], :invalid}) end}
...>     )
...>   ]
...> )
{:error, [:a, :b, :c], :invalid}