GUIDES
GUIDESDOCS
GUIDES

Parameters

params Block

You should do ALL things you want with input parameters by params block and never do it within do_block.
Make sure to declare params within params and all undeclared params will be dropped.
There's a simple example:

params do requires :age, type: Integer, values: 18..65 requires :sex, type: Atom, values: [:male, :female], default: :female requires :name, type: Map do requires :first_name requires :last_name end optional :intro, type: String, regexp: ~r/^[a-z]+$/ optional :avatar, type: File optional :avatar_url, type: String exactly_one_of [:avatar, :avatar_url] end

params Variable within do_block

params variable will be given when params dsl defined.
The initiative value of params is conn.private[:maru_params]

Supported Parameter Types

There are a number of build-in Types:

  • String
  • Integer
  • Float
  • Boolean
  • CharList
  • Atom
  • File
  • Json
  • Base64

You can also use them as :string :integer :float :boolean :char_list :atom :file :json and :base64.

An Maru.Exceptions.InvalidFormat[reason: :illegal] exception will be raised on type change error.

🚧

Atom Parser

Atom type parameter is parsed by String.to_existing_atom, so a values validator is recommended.

📘

Multipart file uploads

If you are using the File type parameter, make sure you include the :multipart parser in your routes

Read more at https://hexdocs.pm/plug/Plug.Parsers.html#module-examples

  plug Plug.Parsers, parsers: [:urlencoded, :multipart, :json],
                    json_decoder: Poison

Custom Parameter Type

You can custom type like this:

defmodule MyColorStruct do defstruct r: 0, g: 0, b: 0 def from_hex(<<r::binary-size(2), g::binary-size(2), b::binary-size(2)>>) do %__MODULE__{ r: String.to_integer(r, 16), g: String.to_integer(g, 16), b: String.to_integer(b, 16), } end end defmodule Maru.Types.Color do use Maru.Type def parse("blue", _), do: "2196F3" |> MyColorStruct.from_hex def parse("red", _), do: "F44336" |> MyColorStruct.from_hex def parse(<<"#", s::binary-size(6)>>, _), do: s |> MyColorStruct.from_hex end pramams do optional :color, type: Color end

And you can define custom type with arguments:

defmodule Maru.Types.Time do use Maru.Type def arguments do [:format] end def parse(input, %{format: "m/d/Y"}) do ... end def parse(input, %{format: "Y-m-d"}) do ... end end requires :time, type: Time, format: "m/d/Y" requires :time, type: Time, format: "Y-m-d"

Pipe Types

Pipe Types is useful for multiple encoded parameters. For example when your parameter value is a json encoded string, you can define your params block like this:

params group :payload, type: Json |> List do group :alert, type: Map do requires :id, type: Integer requires :name, type: String end end end post do xxx end
curl -d 'payload=[{"alert":{"id":4399031,"name":"foo"}}]'

You can also use functions as pipe, for example:

defmodule Test do def f(s) do s |> String.split end end requires :foo, type: fn s -> s end |> (&Test.f/1) |> List

Rename params

You can rename params like this:

params do requires :a, type: String, source: "b" end

And then, you will get %{a: 1} within endpoint by params when client send b = 1.

Validators

There're three build-in validators: regexp values and allow_blank, you can use them like this:

params do requires :id, type: :integer, regexp: ~r/^[0-9]+$/ requires :sex, type: :atom, values: [:female, :male], default: :female optional :age, type: :integer, values: 18..65 end

An Maru.Exceptions.UndefinedValidator exception will be raised if validator not defined.
An Maru.Exception.Validation exception will be raised on validators check error.

mutually_exclusive, exactly_one_of and at_least_one_of can also be used in the same way as grape except that we should use an explicit List.

params do requires :food do optional :meat optional :fish optional :rice at_least_one_of [:meat, :fish, :rice] end group :drink do optional :beer optional :wine optional :juice exactly_one_of [:beer, :wine, :juice] end optional :dessert do optional :cake optional :icecream mutually_exclusive :above_all end end

Custom validators

defmodule Maru.Validations.Length do def validate_param!(attr_name, value, option) do byte(value) in option || Maru.Exceptions.Validation |> raise [param: attr_name, validator: :length, value: value, option: option] end end
params do requires :text, length: 2..6 end

Nested Params

In general, Nested Params can be used in the same way as grape except that we should use List and Map in Elixir instead of Array and Hash in Ruby.

params do optional :preferences, type: List do requires :key requires :value end requires :name, type: Map do requires :first_name requires :last_name end end

One Line List Params

If the type of list value is not a map, you can use List[] to parse it. For this params parser

params do requires :foo, type: List[Integer] requires :bar, type: &String.split(&1, ",") |> List[Integer] end

and this request body,

{ "foo": ["1", "2", "3"], "bar": "1,2,3" }

Both params[:foo] and params[:bar] got [1, 2, 3].

Reusable Params

You can define reusable params using helpers.

defmodule API do helpers do params :name do optional :first_name optional :last_name end end params do use :name end get do params[:first_name] params[:last_name] ... end end

You can also define reusable params using shared helpers.

defmodule SharedParams do use Maru.Helper params :period do optional :start_date optional :end_date end params :pagination do optional :page, type: Integer optional :per_page, type: Integer end end defmodule API do helpers SharedParams params do use [:period, :pagination] end get do ... end end