diff --git a/.travis.yml b/.travis.yml index 35aca92..3c7589c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,29 +1,11 @@ sudo: false language: ruby -before_install: gem install bundler -v 1.17.3 -matrix: - include: - - gemfile: graphql-1.7.gemfile - env: GRAPHQL_RUBY_VERSION=1_7 CI=true - rvm: 2.3.8 - - gemfile: graphql-latest.gemfile - env: GRAPHQL_RUBY_VERSION=LATEST CI=true - rvm: 2.3.8 - - gemfile: graphql-1.7.gemfile - env: GRAPHQL_RUBY_VERSION=1_7 CI=true - rvm: 2.4.5 - - gemfile: graphql-latest.gemfile - env: GRAPHQL_RUBY_VERSION=LATEST CI=true - rvm: 2.4.5 - - gemfile: graphql-1.7.gemfile - env: GRAPHQL_RUBY_VERSION=1_7 CI=true - rvm: 2.5.7 - - gemfile: graphql-latest.gemfile - env: GRAPHQL_RUBY_VERSION=LATEST CI=true - rvm: 2.5.7 - - gemfile: graphql-1.7.gemfile - env: GRAPHQL_RUBY_VERSION=1_7 CI=true - rvm: 2.6.5 - - gemfile: graphql-latest.gemfile - env: GRAPHQL_RUBY_VERSION=LATEST CI=true - rvm: 2.6.5 +before_install: gem install bundler -v 2.1.4 +rvm: + - 2.3.8 + - 2.4.9 + - 2.5.7 + - 2.6.5 + - 2.7.0 +env: + - CI=true diff --git a/Gemfile b/Gemfile index ade3400..e041f73 100644 --- a/Gemfile +++ b/Gemfile @@ -1,8 +1,9 @@ source "https://rubygems.org" -gem "pry" - gem "graphql", "~> 1.10" +gem "pry" +gem 'coveralls' + # Specify your gem's dependencies in graphql-guard.gemspec gemspec diff --git a/README.md b/README.md index df19715..2dc0757 100644 --- a/README.md +++ b/README.md @@ -36,30 +36,31 @@ Define a GraphQL schema: ```ruby # Define a type -PostType = GraphQL::ObjectType.define do - name "Post" - - field :id, !types.ID - field :title, types.String +class PostType < GraphQL::Schema::Object + field :id, ID, null: false + field :title, String, null: true end # Define a query -QueryType = GraphQL::ObjectType.define do - name "Query" +class QueryType < GraphQL::Schema::Object + field :posts, [PostType], null: false do + argument :user_id, ID, required: true + end - field :posts, !types[!PostType] do - argument :user_id, !types.ID - resolve ->(obj, args, ctx) { Post.where(user_id: args[:user_id]) } + def posts(user_id:) + Post.where(user_id: user_id) end end # Define a schema -Schema = GraphQL::Schema.define do +class Schema < GraphQL::Schema + use GraphQL::Execution::Interpreter + use GraphQL::Analysis::AST query QueryType end # Execute query -Schema.execute(query, variables: { user_id: 1 }, context: { current_user: current_user }) +Schema.execute(query, variables: { userId: 1 }, context: { current_user: current_user }) ``` ### Inline policies @@ -67,7 +68,9 @@ Schema.execute(query, variables: { user_id: 1 }, context: { current_user: curren Add `GraphQL::Guard` to your schema:
-Schema = GraphQL::Schema.define do
+class Schema < GraphQL::Schema
+  use GraphQL::Execution::Interpreter
+  use GraphQL::Analysis::AST
   query QueryType
   use GraphQL::Guard.new
 end
@@ -76,22 +79,19 @@ end
 Now you can define `guard` for a field, which will check permissions before resolving the field:
 
 
-QueryType = GraphQL::ObjectType.define do
-  name "Query"
-
-  field :posts, !types[!PostType] do
-    argument :user_id, !types.ID
+class QueryType < GraphQL::Schema::Object
+  field :posts, [PostType], null: false do
+    argument :user_id, ID, required: true
     guard ->(obj, args, ctx) { args[:user_id] == ctx[:current_user].id }
-    ...
   end
+  ...
 end
 
You can also define `guard`, which will be executed for every `*` field in the type:
-PostType = GraphQL::ObjectType.define do
-  name "Post"
+class PostType < GraphQL::Schema::Object
   guard ->(obj, args, ctx) { ctx[:current_user].admin? }
   ...
 end
@@ -120,27 +120,12 @@ class GraphqlPolicy
 end
 
-With `graphql-ruby` gem version >= 1.8 and class-based type definitions, use `camelCased` field names in the policy object. -You'd also need to use `type.metadata` (related to [rmosolgo/graphql-ruby#1429](https://github.com/rmosolgo/graphql-ruby/issues/1429)) to get the type class: - -
-class GraphqlPolicy
-  RULES = {
-    MutationType => {
-      createPost: ->(obj, args, cts) { ctx[:current_user].admin? }
-    }
-  }
-
-  def self.guard(type, field)
-    RULES.dig(type.metadata[:type_class], field)
-  end
-end
-
- Pass this object to `GraphQL::Guard`:
-Schema = GraphQL::Schema.define do
+class Schema < GraphQL::Schema
+  use GraphQL::Execution::Interpreter
+  use GraphQL::Analysis::AST
   query QueryType
   use GraphQL::Guard.new(policy_object: GraphqlPolicy)
 end
@@ -167,8 +152,8 @@ end
 class GraphqlPolicy
   RULES = {
     PostType => {
-      '*': ->(obj, args, ctx) { ctx[:current_user].admin? },                           # <=== 4
-      title: ->(obj, args, ctx) { ctx[:current_user].admin? }                          # <=== 2
+      '*': ->(obj, args, ctx) { ctx[:current_user].admin? },                                # <=== 4
+      title: ->(obj, args, ctx) { ctx[:current_user].admin? }                               # <=== 2
     }
   }
 
@@ -177,13 +162,14 @@ class GraphqlPolicy
   end
 end
 
-PostType = GraphQL::ObjectType.define do
-  name "Post"
-  guard ->(obj, args, ctx) { ctx[:current_user].admin? }                               # <=== 3
-  field :title, !types.String, guard: ->(obj, args, ctx) { ctx[:current_user].admin? } # <=== 1
+class PostType < GraphQL::Schema::Object
+  guard ->(obj, args, ctx) { ctx[:current_user].admin? }                                    # <=== 3
+  field :title, String, null: true, guard: ->(obj, args, ctx) { ctx[:current_user].admin? } # <=== 1
 end
 
-Schema = GraphQL::Schema.define do
+class Schema < GraphQL::Schema
+  use GraphQL::Execution::Interpreter
+  use GraphQL::Analysis::AST
   query QueryType
   use GraphQL::Guard.new(policy_object: GraphqlPolicy)
 end
@@ -211,8 +197,7 @@ class Ability
 end
 
 # Use the ability in your guard
-PostType = GraphQL::ObjectType.define do
-  name "Post"
+class PostType < GraphQL::Schema::Object
   guard ->(post, args, ctx) { ctx[:current_ability].can?(:read, post) }
   ...
 end
@@ -232,8 +217,7 @@ class PostPolicy < ApplicationPolicy
 end
 
 # Use the ability in your guard
-PostType = GraphQL::ObjectType.define do
-  name "Post"
+class PostType < GraphQL::Schema::Object
   guard ->(post, args, ctx) { PostPolicy.new(ctx[:current_user], post).show? }
   ...
 end
@@ -248,14 +232,20 @@ By default `GraphQL::Guard` raises a `GraphQL::Guard::NotAuthorizedError` except
 You can change this behavior, by passing custom `not_authorized` lambda. For example:
 
 
-SchemaWithErrors = GraphQL::Schema.define do
+class SchemaWithErrors < GraphQL::Schema
+  use GraphQL::Execution::Interpreter
+  use GraphQL::Analysis::AST
   query QueryType
   use GraphQL::Guard.new(
     # By default it raises an error
-    # not_authorized: ->(type, field) { raise GraphQL::Guard::NotAuthorizedError.new("#{type}.#{field}") }
+    # not_authorized: ->(type, field) do
+    #   raise GraphQL::Guard::NotAuthorizedError.new("#{type.graphql_definition}.#{field}")
+    # end
 
     # Returns an error in the response
-    not_authorized: ->(type, field) { GraphQL::ExecutionError.new("Not authorized to access #{type}.#{field}") }
+    not_authorized: ->(type, field) do
+      GraphQL::ExecutionError.new("Not authorized to access #{type.graphql_definition}.#{field}")
+    end
   )
 end
 
@@ -300,7 +290,9 @@ class GraphqlPolicy end end -Schema = GraphQL::Schema.define do +class Schema < GraphQL::Schema + use GraphQL::Execution::Interpreter + use GraphQL::Analysis::AST query QueryType mutation MutationType @@ -319,11 +311,9 @@ end It's possible to hide fields from being introspectable and accessible based on the context. For example:
-PostType = GraphQL::ObjectType.define do
-  name "Post"
-
-  field :id, !types.ID
-  field :title, types.String do
+class PostType < GraphQL::Schema::Object
+  field :id, ID, null: false
+  field :title, String, null: true do
     # The field "title" is accessible only for beta testers
     mask ->(ctx) { ctx[:current_user].beta_tester? }
   end
@@ -352,9 +342,8 @@ It's possible to test fields with `guard` in isolation:
 
 
 # Your type
-QueryType = GraphQL::ObjectType.define do
-  name "Query"
-  field :posts, !types[!PostType], guard ->(obj, args, ctx) { ... }
+class QueryType < GraphQL::Schema::Object
+  field :posts, [PostType], null: false, guard ->(obj, args, ctx) { ... }
 end
 
 # Your test
@@ -370,9 +359,8 @@ If you would like to test your fields with policy objects:
 
 
 # Your type
-QueryType = GraphQL::ObjectType.define do
-  name "Query"
-  field :posts, !types[!PostType]
+class QueryType < GraphQL::Schema::Object
+  field :posts, [PostType], null: false
 end
 
 # Your policy object
diff --git a/graphql-1.7.gemfile b/graphql-1.7.gemfile
deleted file mode 100644
index e24d295..0000000
--- a/graphql-1.7.gemfile
+++ /dev/null
@@ -1,8 +0,0 @@
-source "https://rubygems.org"
-
-gem "pry"
-gem 'coveralls'
-
-gem "graphql", "~> 1.7.14"
-
-gemspec
diff --git a/graphql-guard.gemspec b/graphql-guard.gemspec
index 377f387..f8dcec2 100644
--- a/graphql-guard.gemspec
+++ b/graphql-guard.gemspec
@@ -23,9 +23,9 @@ Gem::Specification.new do |spec|
 
   spec.required_ruby_version = '>= 2.1.0' # keyword args
 
-  spec.add_runtime_dependency "graphql", ">= 1.6.0", "< 2"
+  spec.add_runtime_dependency "graphql", ">= 1.10.0", "< 2"
 
-  spec.add_development_dependency "bundler", "~> 1.15"
-  spec.add_development_dependency "rake", "~> 10.0"
+  spec.add_development_dependency "bundler", "~> 2.1"
+  spec.add_development_dependency "rake", "~> 13.0"
   spec.add_development_dependency "rspec", "~> 3.0"
 end
diff --git a/graphql-latest.gemfile b/graphql-latest.gemfile
deleted file mode 100644
index 67ae9ad..0000000
--- a/graphql-latest.gemfile
+++ /dev/null
@@ -1,8 +0,0 @@
-source "https://rubygems.org"
-
-gem "pry"
-gem 'coveralls'
-
-gem "graphql", "~> 1.10"
-
-gemspec
diff --git a/lib/graphql/guard.rb b/lib/graphql/guard.rb
index b059293..f94464d 100644
--- a/lib/graphql/guard.rb
+++ b/lib/graphql/guard.rb
@@ -5,10 +5,19 @@
 
 module GraphQL
   class Guard
+    NotAuthorizedError = Class.new(StandardError)
+
     ANY_FIELD_NAME = :'*'
-    DEFAULT_NOT_AUTHORIZED = ->(type, field) { raise NotAuthorizedError.new("Not authorized to access: #{type}.#{field}") }
+    EXECUTE_FIELD_EVENTS = %w[execute_field execute_field_lazy]
 
-    NotAuthorizedError = Class.new(StandardError)
+    DEFAULT_NOT_AUTHORIZED = ->(type, field) do
+      raise NotAuthorizedError.new("Not authorized to access: #{type.graphql_definition}.#{field}")
+    end
+
+    MASKING_FILTER = ->(schema_member, ctx) do
+      mask = schema_member.graphql_definition.metadata[:mask]
+      mask ? mask.call(ctx) : true
+    end
 
     attr_reader :policy_object, :not_authorized
 
@@ -18,75 +27,65 @@ def initialize(policy_object: nil, not_authorized: DEFAULT_NOT_AUTHORIZED)
     end
 
     def use(schema_definition)
-      schema_definition.instrument(:field, self)
+      if schema_definition.interpreter?
+        schema_definition.tracer(self)
+      else
+        raise "Please use the graphql gem version >= 1.10 with GraphQL::Execution::Interpreter"
+      end
+
       add_schema_masking!(schema_definition)
     end
 
-    def instrument(type, field)
-      guard_proc = guard_proc(type, field)
-      return field unless guard_proc
-
-      old_resolve_proc = field.resolve_proc
-      new_resolve_proc = ->(object, arguments, context) do
-        authorized = guard_proc.call(object, arguments, context)
-
-        if authorized
-          old_resolve_proc.call(object, arguments, context)
-        else
-          not_authorized.call(type, field.name.to_sym)
-        end
+    def trace(event, trace_data)
+      if EXECUTE_FIELD_EVENTS.include?(event)
+        ensure_guarded(trace_data) { yield }
+      else
+        yield
       end
-
-      field.redefine { resolve(new_resolve_proc) }
     end
 
-    def guard_proc(type, field)
-      inline_field_guard(field) ||
+    def find_guard_proc(type, field)
+      inline_guard(field) ||
         policy_object_guard(type, field.name.to_sym) ||
-        inline_type_guard(type) ||
+        inline_guard(type) ||
         policy_object_guard(type, ANY_FIELD_NAME)
     end
 
     private
 
     def add_schema_masking!(schema_definition)
-      default_filter_proc = Proc.new do
-        def default_filter
-          GraphQL::Filter.new(except: default_mask).merge(only: ->(schema_member, ctx) {
-            schema_member.metadata[:mask] ? schema_member.metadata[:mask].call(ctx) : true
-          })
+      schema_definition.class_eval do
+        def self.default_filter
+          GraphQL::Filter.new(except: default_mask).merge(only: MASKING_FILTER)
         end
       end
+    end
+
+    def ensure_guarded(trace_data)
+      field = trace_data[:field]
+      guard_proc = find_guard_proc(field.owner, field)
+      return yield unless guard_proc
 
-      if schema_definition.is_a?(Class) # GraphQL-Ruby version >= 1.10
-        schema_definition.class_eval(&default_filter_proc)
+      if guard_proc.call(trace_data[:object], trace_data[:arguments], trace_data[:query].context)
+        yield
       else
-        schema_definition.target.instance_eval(&default_filter_proc)
+        not_authorized.call(field.owner, field.name.to_sym)
       end
     end
 
     def policy_object_guard(type, field_name)
-      policy_object && policy_object.guard(type, field_name)
+      @policy_object && @policy_object.guard(type.type_class, field_name)
     end
 
-    def inline_field_guard(field)
-      field.metadata[:guard]
-    end
-
-    def inline_type_guard(type)
-      type.metadata[:guard]
+    def inline_guard(type_or_field)
+      type_or_field.graphql_definition.metadata[:guard]
     end
   end
 end
 
-if GraphQL::ObjectType.respond_to?(:accepts_definitions) # GraphQL-Ruby version < 1.8
-  GraphQL::ObjectType.accepts_definitions(guard: GraphQL::Define.assign_metadata_key(:guard))
-  GraphQL::Field.accepts_definitions(guard: GraphQL::Define.assign_metadata_key(:guard))
-  GraphQL::Field.accepts_definitions(mask: GraphQL::Define.assign_metadata_key(:mask))
-end
-
-if defined?(GraphQL::Schema::Object) && GraphQL::Schema::Object.respond_to?(:accepts_definition) # GraphQL-Ruby version >= 1.8
-  GraphQL::Schema::Object.accepts_definition(:guard)
-  GraphQL::Schema::Field.accepts_definition(:guard)
-  GraphQL::Schema::Field.accepts_definition(:mask)
-end
+GraphQL::ObjectType.accepts_definitions(guard: GraphQL::Define.assign_metadata_key(:guard))
+GraphQL::Field.accepts_definitions(guard: GraphQL::Define.assign_metadata_key(:guard))
+GraphQL::Field.accepts_definitions(mask: GraphQL::Define.assign_metadata_key(:mask))
+GraphQL::Schema::Object.accepts_definition(:guard)
+GraphQL::Schema::Field.accepts_definition(:guard)
+GraphQL::Schema::Field.accepts_definition(:mask)
diff --git a/lib/graphql/guard/testing.rb b/lib/graphql/guard/testing.rb
index e944d10..7c447bb 100644
--- a/lib/graphql/guard/testing.rb
+++ b/lib/graphql/guard/testing.rb
@@ -5,32 +5,18 @@ class Field
     NoGuardError = Class.new(StandardError)
 
     def guard(*args)
-      raise NoGuardError.new("Get your field by calling: Type.field_with_guard('#{name}')") unless @__guard_type
-      guard_proc = @__guard_object.guard_proc(@__guard_type, self)
+      raise NoGuardError.new("Get your field by calling: Type.field_with_guard('#{name}')") unless @__guard_instance
+
+      guard_proc = @__guard_instance.find_guard_proc(@__guard_type, self)
       raise NoGuardError.new("Guard lambda does not exist for #{@__guard_type}.#{name}") unless guard_proc
 
       guard_proc.call(*args)
     end
 
-    def __policy_object=(policy_object)
+    def __set_guard_instance(policy_object, guard_type)
       @__policy_object = policy_object
-      @__guard_object = GraphQL::Guard.new(policy_object: policy_object)
-    end
-
-    def __guard_type=(guard_type)
       @__guard_type = guard_type
-    end
-  end
-
-  class ObjectType
-    def field_with_guard(field_name, policy_object = nil)
-      field = get_field(field_name)
-      return unless field
-
-      field.clone.tap do |f|
-        f.__policy_object = policy_object
-        f.__guard_type = self
-      end
+      @__guard_instance = GraphQL::Guard.new(policy_object: policy_object)
     end
   end
 
@@ -41,8 +27,7 @@ def self.field_with_guard(field_name, policy_object = nil)
         return unless field
 
         field.to_graphql.clone.tap do |f|
-          f.__policy_object = policy_object
-          f.__guard_type = self.to_graphql
+          f.__set_guard_instance(policy_object, self.to_graphql)
         end
       end
     end
diff --git a/spec/fixtures/inline_schema.rb b/spec/fixtures/inline_schema.rb
index 5b6a6fc..1b7d7ad 100644
--- a/spec/fixtures/inline_schema.rb
+++ b/spec/fixtures/inline_schema.rb
@@ -1,78 +1,45 @@
 # frozen_string_literal: true
 
 module Inline
-  case ENV['GRAPHQL_RUBY_VERSION']
-  when '1_7'
-    PostType = GraphQL::ObjectType.define do
-      name "Post"
-      guard ->(_post, _args, ctx) { ctx[:current_user].admin? }
-      field :id, !types.ID
-      field :title, types.String
-    end
-
-    QueryType = GraphQL::ObjectType.define do
-      name "Query"
-      field :posts, !types[!PostType] do
-        argument :userId, !types.ID
-        guard ->(_obj, args, ctx) { args[:userId] == ctx[:current_user].id }
-        resolve ->(_obj, args, _ctx) { Post.where(user_id: args[:userId]) }
-      end
+  class PostType < GraphQL::Schema::Object
+    guard ->(_post, _args, ctx) { ctx[:current_user].admin? }
+    field :id, ID, null: false
+    field :title, String, null: true
+  end
 
-      field :postsWithMask, !types[!PostType] do
-        argument :userId, !types.ID
-        mask ->(ctx) { ctx[:current_user].admin? }
-        resolve ->(_obj, args, _ctx) { Post.where(user_id: args[:userId]) }
-      end
+  class QueryType < GraphQL::Schema::Object
+    field :posts, [PostType], null: false do
+      argument :user_id, ID, required: true
+      guard ->(_obj, args, ctx) { args[:user_id] == ctx[:current_user].id }
     end
 
-    Schema = GraphQL::Schema.define do
-      query QueryType
-      use GraphQL::Guard.new
+    field :posts_with_mask, [PostType], null: false do
+      argument :user_id, ID, required: true
+      mask ->(ctx) { ctx[:current_user].admin? }
     end
 
-    SchemaWithoutExceptions = GraphQL::Schema.define do
-      query QueryType
-      use GraphQL::Guard.new(not_authorized: ->(type, field) {
-        GraphQL::ExecutionError.new("Not authorized to access #{type}.#{field}")
-      })
+    def posts(user_id:)
+      Post.where(user_id: user_id)
     end
-  when 'LATEST'
-    class PostType < GraphQL::Schema::Object
-      guard ->(_post, _args, ctx) { ctx[:current_user].admin? }
-      field :id, ID, null: false
-      field :title, String, null: true
-    end
-
-    class QueryType < GraphQL::Schema::Object
-      field :posts, [PostType], null: false do
-        argument :user_id, ID, required: true
-        guard ->(_obj, args, ctx) { args[:userId] == ctx[:current_user].id }
-      end
-
-      field :posts_with_mask, [PostType], null: false do
-        argument :user_id, ID, required: true
-        mask ->(ctx) { ctx[:current_user].admin? }
-      end
 
-      def posts(user_id:)
-        Post.where(user_id: user_id)
-      end
-
-      def posts_with_mask(user_id:)
-        Post.where(user_id: user_id)
-      end
+    def posts_with_mask(user_id:)
+      Post.where(user_id: user_id)
     end
+  end
 
-    class Schema < GraphQL::Schema
-      query QueryType
-      use GraphQL::Guard.new
-    end
+  class Schema < GraphQL::Schema
+    use GraphQL::Execution::Interpreter
+    use GraphQL::Analysis::AST
+    query QueryType
+    use GraphQL::Guard.new
+  end
 
-    class SchemaWithoutExceptions < GraphQL::Schema
-      query QueryType
-      use GraphQL::Guard.new(not_authorized: ->(type, field) {
-        GraphQL::ExecutionError.new("Not authorized to access #{type}.#{field}")
-      })
-    end
+  class SchemaWithoutExceptions < GraphQL::Schema
+    use GraphQL::Execution::Interpreter
+    use GraphQL::Analysis::AST
+    query QueryType
+    use GraphQL::Guard.new(not_authorized: ->(type, field) {
+      GraphQL::ExecutionError.new("Not authorized to access #{type.graphql_definition}.#{field}")
+    })
   end
 end
diff --git a/spec/fixtures/policy_object_schema.rb b/spec/fixtures/policy_object_schema.rb
index 9e2942c..fa9e67a 100644
--- a/spec/fixtures/policy_object_schema.rb
+++ b/spec/fixtures/policy_object_schema.rb
@@ -1,75 +1,40 @@
 # frozen_string_literal: true
 
 module PolicyObject
-  case ENV['GRAPHQL_RUBY_VERSION']
-  when '1_7'
-    PostType = GraphQL::ObjectType.define do
-      name "Post"
-      field :id, !types.ID
-      field :title, types.String
-    end
-
-    QueryType = GraphQL::ObjectType.define do
-      name "Query"
-      field :posts, !types[!PostType] do
-        argument :userId, !types.ID
-        resolve ->(_obj, args, _ctx) { Post.where(user_id: args[:userId]) }
-      end
-    end
-
-    class GraphqlPolicy
-      RULES = {
-        QueryType => {
-          posts: ->(_obj, args, ctx) { args[:userId] == ctx[:current_user].id }
-        },
-        PostType => {
-          '*': ->(_post, args, ctx) { ctx[:current_user].admin? }
-        }
-      }
-
-      def self.guard(type, field)
-        RULES.dig(type, field)
-      end
-    end
+  class PostType < GraphQL::Schema::Object
+    field :id, ID, null: false
+    field :title, String, null: true
+  end
 
-    Schema = GraphQL::Schema.define do
-      query QueryType
-      use GraphQL::Guard.new(policy_object: GraphqlPolicy)
-    end
-  when 'LATEST'
-    class PostType < GraphQL::Schema::Object
-      field :id, ID, null: false
-      field :title, String, null: true
+  class QueryType < GraphQL::Schema::Object
+    field :posts, [PostType], null: false do
+      argument :user_id, ID, required: true
     end
 
-    class QueryType < GraphQL::Schema::Object
-      field :posts, [PostType], null: false do
-        argument :user_id, ID, required: true
-      end
-
-      def posts(user_id:)
-        Post.where(user_id: user_id)
-      end
+    def posts(user_id:)
+      Post.where(user_id: user_id)
     end
+  end
 
-    class GraphqlPolicy
-      RULES = {
-        QueryType => {
-          posts: ->(_obj, args, ctx) { args[:userId] == ctx[:current_user].id }
-        },
-        PostType => {
-          '*': ->(_post, args, ctx) { ctx[:current_user].admin? }
-        }
+  class GraphqlPolicy
+    RULES = {
+      QueryType => {
+        posts: ->(_obj, args, ctx) { args[:user_id] == ctx[:current_user].id }
+      },
+      PostType => {
+        '*': ->(_post, args, ctx) { ctx[:current_user].admin? }
       }
+    }
 
-      def self.guard(type, field)
-        RULES.dig(type.metadata[:type_class], field)
-      end
+    def self.guard(type, field)
+      RULES.dig(type, field)
     end
+  end
 
-    class Schema < GraphQL::Schema
-      query QueryType
-      use GraphQL::Guard.new(policy_object: GraphqlPolicy)
-    end
+  class Schema < GraphQL::Schema
+    use GraphQL::Execution::Interpreter
+    use GraphQL::Analysis::AST
+    query QueryType
+    use GraphQL::Guard.new(policy_object: GraphqlPolicy)
   end
 end
diff --git a/spec/fixtures/without_interpreter_schema.rb b/spec/fixtures/without_interpreter_schema.rb
new file mode 100644
index 0000000..c332bd1
--- /dev/null
+++ b/spec/fixtures/without_interpreter_schema.rb
@@ -0,0 +1,16 @@
+# frozen_string_literal: true
+
+module WithoutInterpreter
+  class QueryType < GraphQL::Schema::Object
+    field :userIds, [String], null: false
+
+    def user_ids
+      ['1', '2']
+    end
+  end
+
+  class Schema < GraphQL::Schema
+    query QueryType
+    use GraphQL::Guard.new
+  end
+end
diff --git a/spec/graphql/guard_spec.rb b/spec/graphql/guard_spec.rb
index 0b4dab0..158394e 100644
--- a/spec/graphql/guard_spec.rb
+++ b/spec/graphql/guard_spec.rb
@@ -13,7 +13,7 @@
       user = User.new(id: '1', role: 'admin')
       query = "query($userId: ID!) { posts(userId: $userId) { id title } }"
 
-      result = Inline::Schema.execute(query, variables: {'userId' => user.id}, context: {current_user: user})
+      result = Inline::Schema.execute(query, variables: {userId: user.id}, context: {current_user: user})
 
       expect(result).to eq({"data" => {"posts" => [{"id" => "1", "title" => "Post Title"}]}})
     end
@@ -23,7 +23,7 @@
       query = "query($userId: ID!) { posts(userId: $userId) { id title } }"
 
       expect {
-        Inline::Schema.execute(query, variables: {'userId' => '2'}, context: {current_user: user})
+        Inline::Schema.execute(query, variables: {userId: 2}, context: {current_user: user})
       }.to raise_error(GraphQL::Guard::NotAuthorizedError, 'Not authorized to access: Query.posts')
     end
 
@@ -32,7 +32,7 @@
       query = "query($userId: ID!) { posts(userId: $userId) { id title } }"
 
       expect {
-        Inline::Schema.execute(query, variables: {'userId' => '1'}, context: {current_user: user})
+        Inline::Schema.execute(query, variables: {userId: 1}, context: {current_user: user})
       }.to raise_error(GraphQL::Guard::NotAuthorizedError, 'Not authorized to access: Post.id')
     end
 
@@ -40,7 +40,7 @@
       user = User.new(id: '1', role: 'not_admin')
       query = "query($userId: ID!) { posts(userId: $userId) { id title } }"
 
-      result = Inline::SchemaWithoutExceptions.execute(query, variables: {'userId' => '1'}, context: {current_user: user})
+      result = Inline::SchemaWithoutExceptions.execute(query, variables: {userId: 1}, context: {current_user: user})
 
       expect(result['errors']).to eq([{
         "message" => "Not authorized to access Post.id",
@@ -56,7 +56,7 @@
       user = User.new(id: '1', role: 'admin')
       query = "query($userId: ID!) { postsWithMask(userId: $userId) { id } }"
 
-      result = Inline::Schema.execute(query, variables: {'userId' => user.id}, context: {current_user: user})
+      result = Inline::Schema.execute(query, variables: {userId: user.id}, context: {current_user: user})
 
       expect(result.to_h).to eq({"data" => {"postsWithMask" => [{"id" => "1"}]}})
     end
@@ -65,23 +65,14 @@
       user = User.new(id: '1', role: 'not_admin')
       query = "query($userId: ID!) { postsWithMask(userId: $userId) { id } }"
 
-      result = Inline::Schema.execute(query, variables: {'userId' => user.id}, context: {current_user: user})
-
-      case ENV['GRAPHQL_RUBY_VERSION']
-      when '1_7'
-        expect(result['errors']).to include({
-          "message" => "Field 'postsWithMask' doesn't exist on type 'Query'",
-          "locations" => [{"line" => 1, "column" => 23}],
-          "fields" => ["query", "postsWithMask"]
-        })
-      when 'LATEST'
-        expect(result['errors']).to include({
-          "message" => "Field 'postsWithMask' doesn't exist on type 'Query'",
-          "locations" => [{"line" => 1, "column" => 23}],
-          "path" => ["query", "postsWithMask"],
-          "extensions" =>  {"code" => "undefinedField", "typeName" => "Query", "fieldName" => "postsWithMask"}
-        })
-      end
+      result = Inline::Schema.execute(query, variables: {userId: user.id}, context: {current_user: user})
+
+      expect(result['errors']).to include({
+        "message" => "Field 'postsWithMask' doesn't exist on type 'Query'",
+        "locations" => [{"line" => 1, "column" => 23}],
+        "path" => ["query", "postsWithMask"],
+        "extensions" =>  {"code" => "undefinedField", "typeName" => "Query", "fieldName" => "postsWithMask"}
+      })
     end
   end
 
@@ -90,7 +81,7 @@
       user = User.new(id: '1', role: 'admin')
       query = "query($userId: ID!) { posts(userId: $userId) { id title } }"
 
-      result = PolicyObject::Schema.execute(query, variables: {'userId' => user.id}, context: {current_user: user})
+      result = PolicyObject::Schema.execute(query, variables: {userId: user.id}, context: {current_user: user})
 
       expect(result).to eq({"data" => {"posts" => [{"id" => "1", "title" => "Post Title"}]}})
     end
@@ -100,7 +91,7 @@
       query = "query($userId: ID!) { posts(userId: $userId) { id title } }"
 
       expect {
-        PolicyObject::Schema.execute(query, variables: {'userId' => '2'}, context: {current_user: user})
+        PolicyObject::Schema.execute(query, variables: {userId: 2}, context: {current_user: user})
       }.to raise_error(GraphQL::Guard::NotAuthorizedError, 'Not authorized to access: Query.posts')
     end
 
@@ -109,8 +100,18 @@
       query = "query($userId: ID!) { posts(userId: $userId) { id title } }"
 
       expect {
-        PolicyObject::Schema.execute(query, variables: {'userId' => '1'}, context: {current_user: user})
+        PolicyObject::Schema.execute(query, variables: {userId: 1}, context: {current_user: user})
       }.to raise_error(GraphQL::Guard::NotAuthorizedError, 'Not authorized to access: Post.id')
     end
   end
+
+  context 'schema without interpreter' do
+    it 'raises an exception' do
+      query = "query { userIds }"
+
+      expect {
+        require 'fixtures/without_interpreter_schema'
+      }.to raise_error('Please use the graphql gem version >= 1.10 with GraphQL::Execution::Interpreter')
+    end
+  end
 end
diff --git a/spec/graphql/testing_spec.rb b/spec/graphql/testing_spec.rb
index 939c020..302f69f 100644
--- a/spec/graphql/testing_spec.rb
+++ b/spec/graphql/testing_spec.rb
@@ -15,7 +15,7 @@
       posts_field = Inline::QueryType.field_with_guard('posts')
       user = User.new(id: '1', role: 'admin')
 
-      result = posts_field.guard(nil, {userId: user.id}, {current_user: user})
+      result = posts_field.guard(nil, {user_id: user.id}, {current_user: user})
 
       expect(result).to eq(true)
     end
@@ -24,7 +24,7 @@
       posts_field = Inline::QueryType.field_with_guard('posts')
       user = User.new(id: '1', role: 'admin')
 
-      result = posts_field.guard(nil, {userId: '2'}, {current_user: user})
+      result = posts_field.guard(nil, {user_id: '2'}, {current_user: user})
 
       expect(result).to eq(false)
     end
@@ -44,7 +44,7 @@
       posts_field = PolicyObject::QueryType.field_with_guard('posts', PolicyObject::GraphqlPolicy)
       user = User.new(id: '1', role: 'admin')
 
-      result = posts_field.guard(nil, {userId: user.id}, {current_user: user})
+      result = posts_field.guard(nil, {user_id: user.id}, {current_user: user})
 
       expect(result).to eq(true)
     end
@@ -54,26 +54,15 @@
       user = User.new(id: '1', role: 'admin')
 
       expect {
-        posts_field.guard(nil, {userId: user.id}, {current_user: user})
+        posts_field.guard(nil, {user_id: user.id}, {current_user: user})
       }.to raise_error(GraphQL::Field::NoGuardError, "Guard lambda does not exist for Query.posts")
     end
 
-    if ENV['GRAPHQL_RUBY_VERSION'] == '1_7'
-    it 'raises an error if the field was fetched without guard' do
-      posts_field = PolicyObject::QueryType.get_field('posts')
-      user = User.new(id: '1', role: 'admin')
-
-      expect {
-        posts_field.guard(nil, {userId: user.id}, {current_user: user})
-      }.to raise_error(GraphQL::Field::NoGuardError, "Get your field by calling: Type.field_with_guard('posts')")
-    end
-    end
-
     it 'returns false for a not authorized field' do
       posts_field = PolicyObject::QueryType.field_with_guard('posts', PolicyObject::GraphqlPolicy)
       user = User.new(id: '1', role: 'admin')
 
-      result = posts_field.guard(nil, {userId: '2'}, {current_user: user})
+      result = posts_field.guard(nil, {user_id: '2'}, {current_user: user})
 
       expect(result).to eq(false)
     end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 129e314..f19d8ec 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -2,8 +2,6 @@
 
 require "bundler/setup"
 
-ENV['GRAPHQL_RUBY_VERSION'] ||= 'LATEST'
-
 if ENV['CI']
   require 'simplecov'
   SimpleCov.add_filter('spec')