Sometimes, you want to hide schema elements from some users. For example:
If you only want to limit access to these fields, consider using the authorization framework.
If you want to completely hide some fields, types, enum values or arguments, read on!
You can hide parts of the schema by passing except:
or only:
to Schema.execute
. For example:
# `except:` blacklists items:
filter = PermissionBlacklist.new(@current_user)
MySchema.execute(query_string, except: filter)
# OR
# `only:` whitelists items:
filter = PermissionWhitelist.new(@current_user)
MySchema.execute(query_string, only: filter)
During that query, some elements will be hidden. This means that fields, types, arguments or enum values will be treated as if they were not defined at all.
A filter must respond to #call(schema_member, ctx)
. When that method returns truthy, the schema member will be blacklisted or whitelisted.
For example, here’s an implementation of PermissionWhitelist
above:
class PermissionWhitelist
def initialize(person)
@person = person
end
# If this returns true, the schema member will be allowed
def call(schema_member, ctx)
Permissions.allowed?(person, schema_member)
end
end
The schema_member
may be any of:
GraphQL::BaseType
and subclasses)GraphQL::Field
)GraphQL::Argument
)GraphQL::EnumType::EnumValue
)This feature pairs nicely with attaching custom data to types. See the Extensions Guide for information about assigning values to an object’s metadata
.
Then, you can check metadata
in your filter. For example, to hide fields based on a metadata flag:
# Hide secret objects from this user
top_secret = ->(schema_member, ctx) { schema_member.metadata[:top_secret]}
MySchema.execute(query_string, except: top_secret)
You can see how filters will be applied to the schema by printing the schema with that filter. GraphQL::Schema#to_definition
accepts only:
and except:
options.
For example, to see how the schema looks to a specific user:
example_user = User.new(permission: :admin)
filter = PermissionWhitelist.new(example_user)
defn_string = MySchema.to_definition(only: filter)
puts defn_string
# => prints out the filtered schema
Schema#to_definition
also accepts a context which will be passed to the filter as well, for example:
context = { current_user: example_user }
puts MySchema.to_definition(only: filter, context: context)