How to add validation to a custom type via Ash.Types.NewType?

I want to create some custom ash types that has some extra validation, for example:

defmodule Core.Jobs.Types.Url do
  @moduledoc false

  use Ash.Type.NewType,
      subtype_of: :string

  def apply_constraints(value, constraints) do
    uri = URI.parse(value)

    cond do
      is_nil(uri.scheme) or is_nil(uri.host) ->
        {:error, "invalid URL"}

      uri.scheme not in ["http", "https"] ->
        {:error, "only http/https URLs allowed"}

      true ->
        :ok
    end
  end
end

Since I only want to configure the validation part of the type, I’m using Ash.Types.NewType with a subtype of :string.

The issue is that I can’t figure out how to add the validation to the type, I tried overriding the apply_constraints/2 function, but this doesn’t seem to work at all.

Is this possible or do I need to create a full blown Ash.Type if I want to add some kind of validation to it?

1 Like

IIRC the best way to accomplish this is via overriding def cast_input/2. Mind giving that a shot?

1 Like

Yes, worked great, thanks!

defmodule Core.Jobs.Types.Url do
  @moduledoc false

  use Ash.Type.NewType,
    subtype_of: :string

  @impl true
  def cast_input(value, _constraints) when is_binary(value) do
    uri = URI.parse(value)

    cond do
      is_nil(uri.scheme) or is_nil(uri.host) ->
        {:error, "invalid URL"}

      uri.scheme not in ["http", "https"] ->
        {:error, "only http/https URLs allowed"}

      true ->
        {:ok, value}
    end
  end

  def cast_input(_value, _constraints), do: {:error, "value must be a string"}
end