Absinthe - Validation of values in input object/args

Hi all,

I ran into this scenario while running Absinthe GQL with Phoenix, I have this query that look as a follows:

object :admin_queries do 
   field :get_user, non_null(:user) do 
     arg :input, non_null(:user_input) 
     resolve(&Resolvers.User.get_user/2)
   end
end

input_object :user_input do 
  field :id, non_null(:id) 
end

When I tried to run this query, I realized that is allowed for the following to pass

query getUser( {
 input { id: "" }
})  {
    id
    name
}

correctly so, since an "" != null.

I tried to reason about how to handle the validation of id (and in extension other fields too), and I came to the following plausible solutions:

  1. Use middleware, but its too deep in the resolution and it was a challenge to use when you need to validate nested inputs. As an example, see what that looks like below:
defmodule Gql.Middleware.ValidateUuid do 
  @behaviour Absinthe.Middleware
  def call(%Resolution{arguments: %{merchant_id: merchant_id}} = resolution, _),
    do: validate_uuid(resolution, merchant_id, :merchant_id)

  def call(%Resolution{arguments: %{delivery_id: delivery_id}} = resolution, _),
    do: validate_uuid(resolution, delivery_id, :delivery_id)

  def call(%Resolution{arguments: %{user_id: user_id}} = resolution, _),
    do: validate_uuid(resolution, user_id, :user_id)

  def call(%Resolution{arguments: %{id: id}} = resolution, _),
    do: validate_uuid(resolution, id, :id)

  def call(%Resolution{arguments: %{input: %{user_id: user_id}}} = resolution, _),
    do: validate_uuid(resolution, user_id, :user_id)
....
  1. Build my own scalar type, but that would result in breaking changes in my client and the naming of the type will change, which is not ideal, within which I would use the parse macro to handle my validations.
 scalar :uuid, name: "UUID" do
    parse(&parse_custom/1)
  end
  1. Handle all validation in the resolver, it would result to a lot more changes in each resolver.

My question is, is there a way to handle this more seamlessly?
In an ideal world, i think it would be awesome to have the middleware available in args or field
in input_object.

Thanks in advance

I found this library that does the job.