How can I access request aguements from a field resolver in Absinthe?

Let’s say I have a Location schema. User’s can search for Locations by name. I also want to add a distance field if they pass in coords, and their query requests that field (I don’t want to calculate it in the resolve, in the case their request doesn’t need that field)

object :location do
  field(:id, :string)
  field(:name, :string)
  field(:distance, :float, resolve: fn %{coords: location_coords},  _, _ ->
     user_coords
    {:ok, distance_between(location_coords, user_coords}
  end)

The request would look like this:

query SearchLocations($input: SearchLocationsInput!) {
  searchLocations(input: $input) {
    id
    name
    distance
  }
}

and the variables:

input: {
  query: "something",
  coords: {
    latitude: xx.xx,
    longitude: yy.yy
  }
}

How can I access the coords from the object field resolver? When I inspect the 3 args, the first is the Location, the second is an empty map, the third is a Absinthe.Resolution struct.

To have arguments in distance field you have to declare them and pass data to it:

{
  searchLocations(input: $input) {
    id
    name
    distance(coords: $coords)
  }
}
input_object :coords do
  field(:latitude, non_null(:float))
  field(:longitude, non_null(:float))
end

field(:distance, :float) do
  arg(:coords, :coords)
  resolve(...)
end

Otherwise, you have to calculate coords in parent resolver for every location and insert the data using virtual field.

Is there anyway to pull it out of $input which already had the coords (I’m also using them in the Location query to order).
Something like this? Though this doesn’t work.

{
  searchLocations(input: $input) {
    id
    name
    distance(coords: $input.coords)
  }
}

If it is the same value, you can also pass the data from the parent field to the child field by returning it as part of the searchLocations resolver return value.

As a reference for the future to anyone else searching on this topic, you can check out the official docs
https://hexdocs.pm/absinthe/query-arguments.html#arguments-and-non-root-fields

Those docs explain a different use case to what I was asking about.

The docs example uses:

{
  user(id: "1") {
    name
    posts(date: "2017-01-01") {
      title
      body
      publishedAt
    }
  }
}

I was trying to achevie a similar thing, but if the query was:

{
  user(id: "1", date: "2017-01-01") {
    name
    posts {
      title
      body
      publishedAt
    }
  }
}

Now how can I access the date within the posts resolver?

@pejrich you have some options, but it can be a bit fragile if you aren’t careful. Consider a different query:

{
  post(id: 1) {
    author {
      posts { title body }
   }
  }
}

In this case it’s still the posts field on a user object, but the overall path way is different such that those parent fields don’t exist.

So instead, I’d recommend something more like:

query ($date: Date!) {
  user(id: "1", date: $date) {
    name
    posts(publishedOn: $date) {
      title
      body
      publishedAt
    }
  }
}

This helps tie things together explicitly, while still not creating inflexible dependencies on the query path in the document.

Tangentially: What does it mean to get a user by id and date in the first place?

@pejrich I got it. You can easily get the date value under resolver of posts from arguments by passing a map value for posts. Like

object :user_data do
    other fields,
    field :posts, :post
end

object :post do
    other fields,
    field :date, :date
end

object :query do
 
    field :user, :user_data do
    	arg(:id, :string)
    	arg(:date, :date)
    
    	resolve(&User.get_user_data/2)
    end 

 end

The get_user_data resolver function like this under the User module.

 def get_user_data(args, _) do
 	%{ 
 		name: "",
 		posts: 
	 	 %{
	 	  title: "", 
	 	  body: "", 			 
	 	  publishedAt: args.date
	 	 }
 	}
 end

It will automatically pass the date under the within the post resolver from arguments.