Graphql-ruby: Field classes in the class-based API

Created on 3 May 2018  路  9Comments  路  Source: rmosolgo/graphql-ruby

In the class-based API, is there a way to define field classes and hook them up to fields in your schema similar to how Mutation classes work?

This would help to reduce the clutter in my top-level Types::Query by externalizing field arguments and resolver functions to a separate file. There may be some other benefits as well (parity with mutations, reusing fields on different types, etc.)

Most helpful comment

I am also in favor of this. Being able to inherit from an ApplicationQuery would be super useful to allow us to remain writing conventional Ruby instead of the more pure-functional style.

Something like the following interface would feel really natural:

module Types
  class Query < GraphQL::Schema::Object
    field :search, query: Queries::Search
  end
end

module Queries
  class ApplicationQuery
    def current_user
      ctx[:current_user]
    end
  end
end

module Queries
  class Search < ApplicationQuery
    argument :search, Types::SearchInput
    type Types::Search
    def resolve(search)
      if(current_user)
        PrivateSearch.new(user: current_user, parameters: search)
      else
        PublicSearch.new(parameters: search)
      end
    end
  end
end

All 9 comments

Not yet, but that's a really interesting question!

To be honest, there's _room_ for some superclass of Mutation which is "just" a field, expressed as a class. In this way, it's something that takes the place of GraphQL::Mutation.

I'll think on it a bit and try something out, I wonder if anyone else has thought about it ...

That was my thinking as well. I mentioned it in Slack a couple days ago and it didn't garner much attention so I'm not sure how big of a need there is. Nevertheless, I think it would be a nice unification to have the option to write things like

# types/query.rb
field :comments, class: Queries::Comments

# types/mutation.rb
field :add_comment, class: Mutations::AddComment

# types/subscription.rb
field :comment_changed, class: Subscriptions::CommentChanged

Personally I think there is a need, GraphQL::Function is not quite right but we need the ability to split out code. I took a try in #1472; it's not quite there yet but it's a start.

I am also in favor of this. Being able to inherit from an ApplicationQuery would be super useful to allow us to remain writing conventional Ruby instead of the more pure-functional style.

Something like the following interface would feel really natural:

module Types
  class Query < GraphQL::Schema::Object
    field :search, query: Queries::Search
  end
end

module Queries
  class ApplicationQuery
    def current_user
      ctx[:current_user]
    end
  end
end

module Queries
  class Search < ApplicationQuery
    argument :search, Types::SearchInput
    type Types::Search
    def resolve(search)
      if(current_user)
        PrivateSearch.new(user: current_user, parameters: search)
      else
        PublicSearch.new(parameters: search)
      end
    end
  end
end

@zspencer This is actually possible now in 1.8 as of https://github.com/rmosolgo/graphql-ruby/pull/1472. Your example would look like this:

module Types
  class Query < GraphQL::Schema::Object
    field :search, resolver: Queries::Search
  end
end

module Queries
  class ApplicationQuery < GraphQL::Schema::Resolver
    def current_user
      context[:current_user]
    end
  end
end

module Queries
  class Search < ApplicationQuery
    argument :search, Types::SearchInput
    type Types::Search
    def resolve(search)
      if(current_user)
        PrivateSearch.new(user: current_user, parameters: search)
      else
        PublicSearch.new(parameters: search)
      end
    end
  end
end

Here is the diff: https://gist.github.com/mmun/aba5bb47dbc9a59ddda2a7702fc5bb50/revisions

Excellent! Thank you! I was reading through the docs and the examples and not finding anything like this, so I started going with the 'pass in a thing that responds to call' route and decided I didn't like it :).

Awesome! It took a while to find this thread though. @rmosolgo do you think this should be added to the docs?

Sure, feel free to add it!

I will try to do it this weekend!

Was this page helpful?
0 / 5 - 0 ratings