defmodule ToweropsWeb.Api.ErrorHelpers do @moduledoc "Shared error translation helpers for API controllers." @doc """ Translates changeset errors into a map of field names to error message lists. Interpolates message parameters (e.g. `%{count}`) safely, validating keys before atom conversion to prevent atom exhaustion attacks. """ @spec translate_errors(Ecto.Changeset.t()) :: %{atom() => [String.t()]} def translate_errors(changeset) do Ecto.Changeset.traverse_errors(changeset, fn {msg, opts} -> Regex.replace(~r"%{(\w+)}", msg, fn _, key -> safe_translate_key(key, opts) end) end) end defp safe_translate_key(key, opts) do if String.length(key) <= 50 and String.match?(key, ~r/^[a-z_]+$/) do opts |> Keyword.get(String.to_existing_atom(key), key) |> to_string() else key end end end