Inspired by Ruby on Rails Strong Parameters. It filters request params keeping only explicitly enumerated parameters.
In addition, parameters can be marked as required and flow through a controller fallback flow to end up as a 400 Bad Request with no effort.
Add StrongParams
to your application
mix.exs
def deps do
[
{:strong_params, "~> 0.4.1"}
]
end
Update deps
mix deps.get
StrongParams
uses macros to apply the parameters filter. You must use
StrongParams
in each controller you want filter parameters. The better way is using StrongParams
in you Phoenix App entrypoint inside controller/0
block (it must be add after
use Phoenix.Controller
).
/lib/your_phoenix_app.ex
defmodule YourPhoenixApp do
...
def controller do
quote do
use Phoenix.Controller, namespace: YourPhoenixApp
use StrongParams
...
end
end
end
Then you can use macro filter_for/2
inside your controller to apply the filters
for each action.
defmodule YourPhoenixApp.UserController do
use YourPhoenixApp, :controller
alias YourPhoenixApp.User
filter_for(:create, required: [:name, :email], permitted: [:nickname])
def create(conn, %{name: _, email: _} = params) do
user = %User{}
|> User.changeset(params)
|> Repo.insert()
render(conn, user: user)
end
end
In above example, once filter_for/2
is defined for action create
the second
argument received in action will be the filtered request parameters. The map params
has atomized keys, once the filter is defined as atoms
(the lib don't create new atoms).
If some parameter enumerated as required is missing in received request the Plug.Conn
will be halted with status code 400
and a generic error message. If you add an
action fallback you can handle the filter error:
defmodule YourPhoenixApp.UserController do
use YourPhoenixApp, :controller
action_fallback(YourPhoenixApp.Fallback)
filter_for(:create, required: [:name, :email], permitted: [:nickname])
...
end
defmodule YourPhoenixApp.Fallback do
alias StrongParams.Error
def call(conn, %Error{errors: errors}) do
send_resp(conn, 400, "Your custom msg #{inpect(errors)}")
end
end
You must call filter_for/2
for each action you want to filter the params.
filter_for(:create, required: [:name, :email], permitted: [:nickname])
filter_for(:update, permitted: [:name, :email, :nickname])