SafeAtom.Plug (SafeAtom v0.3.0)

Copy Markdown View Source

Casts named request parameters against per-field atom whitelists.

Configured field names are atoms, while request param lookups use their string forms. Successful values remain under string keys. Rejected values are dropped by default.

Module plug

plug SafeAtom.Plug,
  fields: %{status: [:active, :archived], sort: [:asc, :desc]}

Use on_reject: :halt to send a 400 response and halt the connection. For application-specific handling in a module plug, pass an escapable external remote function capture:

defmodule MyApp.ParamPipeline do
  use Plug.Builder

  plug SafeAtom.Plug,
    fields: %{status: [:active, :archived]},
    on_reject: &__MODULE__.handle_rejection/2

  def handle_rejection(conn, rejection) do
    Plug.Conn.assign(conn, :safe_atom_rejection, rejection)
  end
end

The function receives the connection and a SafeAtom.Plug.Rejection. Plug.Builder cannot escape anonymous closures in initialized module-plug options. Direct calls to cast_params/3 accept any two-arity function, including closures.

Function plug

iex> conn = Plug.Test.conn(:get, "/")
iex> conn = %{conn | params: %{"status" => "active", "query" => "keep"}}
iex> conn = SafeAtom.Plug.cast_params(conn, %{status: [:active, :archived]})
iex> conn.params
%{"query" => "keep", "status" => :active}

iex> conn = Plug.Test.conn(:get, "/")
iex> conn = %{conn | params: %{"status" => "deleted"}}
iex> conn = SafeAtom.Plug.cast_params(conn, %{status: [:active]})
iex> conn.params
%{}

Summary

Types

fields()

@type fields() :: %{required(atom()) => [atom()]}

on_reject()

@type on_reject() ::
  :drop | :halt | (Plug.Conn.t(), SafeAtom.Plug.Rejection.t() -> Plug.Conn.t())

Functions

cast_params(conn, fields, opts \\ [])

@spec cast_params(Plug.Conn.t(), fields(), keyword()) :: Plug.Conn.t()