When a Changeset is a Plug

This article has been moved to: https://supersimple.org/blog/changeset-plug

Photo Credit: Marco Verch
Ecto.Query.CastError: lib/project/queries/project_query.ex:238: value `"xyz"` cannot be dumped to type :binary_id in query
defmodule ProjectWeb.IDValidatorPlug do
@moduledoc """
Takes the params from `conn` and validates any IDs are in the
correct format.

@params_to_validate ~w[id project_id]

def init(opts), do: opts

@spec call(Plug.Conn.t(), list()) :: no_return()
def call(conn, opts \\ [])

def call(%{params: _params} = conn, _opts) do
has_errors? =
|> Plug.Conn.fetch_query_params()
|> Map.get(:params)
|> Enum.filter(fn {k, _v} -> k in @params_to_validate end)
|> Enum.map(fn {_k, v} -> Ecto.UUID.cast(v) end)
|> Enum.member?(:error)

case has_errors? do
true -> halt_with(422, "The ID provided was not in the correct format", conn)
_ -> conn

def call(conn, _opts), do: conn
defp halt_with(code, message, conn) do
|> put_status(code)
|> Phoenix.Controller.put_view(ProjectWeb.ErrorView)
|> Phoenix.Controller.render("#{code}.json", %{
message: "#{message}",
status: "#{code}"
|> halt()

Software Engineer — https://supersimple.org/blog/

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store