How to resolve sub-fields such that they add optional parameters to HTTP query?

1.5k views Asked by At

Note: this is a greatly simplified example but the problem is the same.

I am trying to wrap an existing HTTP service, /blog-posts, with a GraphQL interface. The service returns some extra data in its response only if I pass in a query parameter, extra-data=true. So,

  • GET /blog-posts: gets ID and title
  • GET /blog-posts?extra-data=true: gets ID, title, and extra-data field

I have an Absinthe schema similar to the following:

query do
  field :blog_posts, non_null(list_of(non_null(:blog_post)))
  resolve &MyAppWeb.Resolvers.Blog.posts/3
end

object :blog_post do
  field :id, non_null(:id)
  field :title, non_null(:string)
  field :extra_data, :string,
    resolve: &MyAppWeb.Resolvers.Blog.post_extra_data/3
end

My problem is I don't know how to implement the extra_data resolver such that it doesn't make a redundant call to /blog-posts?extra-data=true after already having called /blog-posts. There is a middleware https://hexdocs.pm/absinthe/Absinthe.Middleware.Batch.html that is designed to help with a similar problem, N+1 queries, but I don't see how to apply it in my case.

Any suggestions?

1

There are 1 answers

7
Sheharyar On

One Optional Field

If it's just one extra field, you can pass an optional argument in your query:

query do
  field :blog_posts, list_of(:blog_post) do
    arg :extra_data, :boolean
    resolve &MyAppWeb.Resolvers.Blog.posts/2
  end
end

Multiple Extra Fields

But, if there are multiple optional arguments, it's better to use a custom input_object:

input_object :extra_input do
  field :extra_a, :boolean
  field :extra_b, :boolean
  field :extra_c, :boolean
end

query do
  field :blog_posts, list_of(:blog_post) do
    arg :extra_fields, :extra_input
    resolve &MyAppWeb.Resolvers.Blog.posts/2
  end
end

And in your resolver, you can get the request fields and build your HTTP request URL with them:

def posts(%{extra_fields: extra}, _resolution) do
  # Here `extra` is a map of the optional fields requested. You can
  # filter selected fields, map them to their HTTP service name and
  # construct the HTTP url and query params before calling it in
  # one go
end

In both cases, remove the resolver you've specified directly on the :extra_data field in your :blog_post object.