One way is to use the Ecto.Changeset.validate_change/3 function instead of validate_format. You will have to figure out how to write the callback function yourself, but there is an example in the documentation
To add to this: changeset validations (and their errors) are on a per field basis. So you either need to have a custom validation for checking the individual items of an array of them as suggested, or if you want more fine grained errors/validations consider embeds_many over arrays of something.
You’d definitely have to create a custom validator using Ecto.Changeset.validate_change/3.
If you want to use the existing API for a single element, then you can use schemaless changeset with a single element like this:
defmodule MyHelper do
def validate_array(changeset, field, map_single_element_changeset_callback) do
changeset = Ecto.Changeset.change(changeset)
{:array, single_element_type} = changeset.types[field]
changeset
|> Ecto.Changeset.validate_change(field, fn _, values ->
error =
Enum.find_value(values, fn value ->
{%{}, %{value: single_element_type}}
|> Ecto.Changeset.cast(%{value: value}, [:value])
|> map_single_element_changeset_callback.()
|> Ecto.Changeset.apply_action(:insert)
|> case do
{:ok, _} ->
nil
{:error, changeset} ->
{message, _meta} = changeset.errors[:value]
{message, value}
end
end)
case error do
nil ->
[]
{message, value} ->
[{field, "contains invalid element #{value}: #{message}"}]
end
end)
end
end