Class: GraphQL::Schema::Warden Private

Inherits:
Object
  • Object
show all
Defined in:
lib/graphql/schema/warden.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

Restrict access to a GraphQL::Schema with a user-defined filter.

When validating and executing a query, all access to schema members should go through a warden. If you access the schema directly, you may show a client something that it shouldn't be allowed to see.

Examples:

Hidding private fields

private_members = -> (member, ctx) { member.[:private] }
result = Schema.execute(query_string, except: private_members)

Custom filter implementation

# It must respond to `#call(member)`.
class MissingRequiredFlags
  def initialize(user)
    @user = user
  end

  # Return `false` if any required flags are missing
  def call(member, ctx)
    member.[:required_flags].any? do |flag|
      !@user.has_flag?(flag)
    end
  end
end

# Then, use the custom filter in query:
missing_required_flags = MissingRequiredFlags.new(current_user)

# This query can only access members which match the user's flags
result = Schema.execute(query_string, except: missing_required_flags)

Direct Known Subclasses

Query::NullContext::NullWarden

Instance Method Summary collapse

Constructor Details

#initialize(filter, context:, schema:) ⇒ Warden

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of Warden.


44
45
46
47
48
49
50
51
52
# File 'lib/graphql/schema/warden.rb', line 44

def initialize(filter, context:, schema:)
  @schema = schema.interpreter? ? schema : schema.graphql_definition
  # Cache these to avoid repeated hits to the inheritance chain when one isn't present
  @query = @schema.query
  @mutation = @schema.mutation
  @subscription = @schema.subscription
  @context = context
  @visibility_cache = read_through { |m| filter.call(m, context) }
end

Instance Method Details

#arguments(argument_owner) ⇒ Array<GraphQL::Argument>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns Visible arguments on argument_owner.


127
128
129
130
# File 'lib/graphql/schema/warden.rb', line 127

def arguments(argument_owner)
  @visible_arguments ||= read_through { |o| o.arguments.each_value.select { |a| visible_argument?(a) } }
  @visible_arguments[argument_owner]
end

#directivesObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


144
145
146
# File 'lib/graphql/schema/warden.rb', line 144

def directives
  @schema.directives.each_value.select { |d| visible?(d) }
end

#enum_values(enum_defn) ⇒ Array<GraphQL::EnumType::EnumValue>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns Visible members of enum_defn.


133
134
135
136
# File 'lib/graphql/schema/warden.rb', line 133

def enum_values(enum_defn)
  @visible_enum_values ||= read_through { |e| e.values.each_value.select { |enum_value_defn| visible?(enum_value_defn) } }
  @visible_enum_values[enum_defn]
end

#fields(type_defn) ⇒ Array<GraphQL::Field>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns Fields on type_defn.


120
121
122
123
# File 'lib/graphql/schema/warden.rb', line 120

def fields(type_defn)
  @visible_fields ||= read_through { |t| @schema.get_fields(t).each_value.select { |f| visible_field?(t, f) } }
  @visible_fields[type_defn]
end

#get_field(parent_type, field_name) ⇒ GraphQL::Field?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns The field named field_name on parent_type, if it exists.


93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/graphql/schema/warden.rb', line 93

def get_field(parent_type, field_name)

  @visible_parent_fields ||= read_through do |type|
    read_through do |f_name|
      field_defn = @schema.get_field(type, f_name)
      if field_defn && visible_field?(type, field_defn)
        field_defn
      else
        nil
      end
    end
  end

  @visible_parent_fields[parent_type][field_name]
end

#get_type(type_name) ⇒ GraphQL::BaseType?

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns The type named type_name, if it exists (else nil).


68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/graphql/schema/warden.rb', line 68

def get_type(type_name)
  @visible_types ||= read_through do |name|
    type_defn = @schema.get_type(name)
    if type_defn && visible_type?(type_defn)
      type_defn
    else
      nil
    end
  end

  @visible_types[type_name]
end

#interfaces(obj_type) ⇒ Array<GraphQL::InterfaceType>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns Visible interfaces implemented by obj_type.


139
140
141
142
# File 'lib/graphql/schema/warden.rb', line 139

def interfaces(obj_type)
  @visible_interfaces ||= read_through { |t| t.interfaces(@context).select { |i| visible?(i) } }
  @visible_interfaces[obj_type]
end

#possible_types(type_defn) ⇒ Array<GraphQL::BaseType>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns The types which may be member of type_defn.


110
111
112
113
114
115
116
# File 'lib/graphql/schema/warden.rb', line 110

def possible_types(type_defn)
  @visible_possible_types ||= read_through { |type_defn|
    pt = @schema.possible_types(type_defn, @context)
    pt.select { |t| visible_type?(t) }
  }
  @visible_possible_types[type_defn]
end

#reachable_type?(type_name) ⇒ Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns Boolean True if the type is visible and reachable in the schema.


87
88
89
90
# File 'lib/graphql/schema/warden.rb', line 87

def reachable_type?(type_name)
  type = get_type(type_name)
  type && reachable_type_set.include?(type)
end

#reachable_typesArray<GraphQL::BaseType>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns Visible and reachable types in the schema.


82
83
84
# File 'lib/graphql/schema/warden.rb', line 82

def reachable_types
  @reachable_types ||= reachable_type_set.to_a
end

#root_type_for_operation(op_name) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.


148
149
150
151
152
153
154
155
# File 'lib/graphql/schema/warden.rb', line 148

def root_type_for_operation(op_name)
  root_type = @schema.root_type_for_operation(op_name)
  if root_type && visible?(root_type)
    root_type
  else
    nil
  end
end

#typesArray<GraphQL::BaseType>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns Visible types in the schema.


55
56
57
58
59
60
61
62
63
64
65
# File 'lib/graphql/schema/warden.rb', line 55

def types
  @types ||= begin
    vis_types = {}
    @schema.types.each do |n, t|
      if visible_type?(t)
        vis_types[n] = t
      end
    end
    vis_types
  end
end