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"}
]
endUpdate deps
mix deps.getStrongParams 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
endThen 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
endIn 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
endYou 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])