def show(conn, %{"id" => id}) do
with {:ok, user} <- UserAction.get_user(id)
|> put_status(200)
|> render("show.json", %{user: user})
else
{:error, :not_found} -> {:error, :not_found, %User{id: id}}
end
end
When id is invalid, Ecto
raises:
Ecto.Query.CastError - cannot be dumped to type :binary_id in query.
My get_user
function:
query = from(u in User, where u.id == ^id)
case Repo.all(query) do
[%User{} = user] -> {:ok, user}
_ -> {:error, :not_found}
end
Is there any convenient way for handling this error to prevent 500 responses?
That's a known issue with UUID
, Binary
and other ecto types that need to conform to a specific standard (It's a feature, not a bug™️). Like @TheAnh mentioned, you can use Ecto.UUID.dump/1
to check if the id
is valid, but I prefer straight-up rescuing it:
def get_user(id) do
Repo.get(User, id)
rescue
Ecto.Query.CastError -> nil
end
Repo
The above example can get tedious because you'll have to rescue
everywhere you call get
. So I override the get/3
function in MyApp.Repo
:
# lib/my_app/repo.ex
defoverridable [get: 2, get: 3]
def get(query, id, opts \\ []) do
super(query, id, opts)
rescue
Ecto.Query.CastError -> nil
end
fetch
for Tuple formatYou should use fetch_*
method names instead of get_*
to return values in tuple
format (to avoid confusion with default Repo
methods):
# lib/my_app/repo.ex
def fetch(query, id, opts \\ []) do
case get(query, id, opts) do
nil -> {:error, :not_found}
schema -> {:ok, schema}
end
end
And call it like this in your main function:
def fetch_user(id) do
Repo.fetch(User, id)
end
I've ended up with guard macros
defmacro is_uuid(value) do
quote do
is_binary(unquote(value)) and byte_size(unquote(value)) == 36 and
binary_part(unquote(value), 8, 1) == "-" and binary_part(unquote(value), 13, 1) == "-" and
binary_part(unquote(value), 18, 1) == "-" and binary_part(unquote(value), 23, 1) == "-"
end
end
Usage:
def get_user(id) when is_uuid(id) do
Repo.get(User, id)
end
def get_user(_id), do: {:error, :not_found}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With