Created
July 13, 2023 15:29
-
-
Save rmosolgo/bd885348da2e39615b0ac55f369ce44c to your computer and use it in GitHub Desktop.
Hiding introspection fields with GraphQL-Ruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require "bundler/inline" | |
gemfile do | |
gem "graphql", "2.0.24" | |
end | |
class MySchema < GraphQL::Schema | |
module CustomIntrospection | |
module HideIntrospectionByContext | |
def visible?(ctx) | |
super && | |
if introspection? | |
ctx[:introspection_permitted] | |
else | |
true | |
end | |
end | |
end | |
class IntrospectionField < GraphQL::Schema::Field | |
include HideIntrospectionByContext | |
end | |
class DynamicFields < GraphQL::Introspection::DynamicFields | |
field_class(IntrospectionField) | |
field :__typename, String, null: false | |
end | |
class EntryPoints < GraphQL::Introspection::EntryPoints | |
field_class(IntrospectionField) | |
field :__type, GraphQL::Introspection::TypeType do | |
argument :name, String | |
end | |
end | |
class SchemaType < GraphQL::Introspection::SchemaType | |
extend HideIntrospectionByContext | |
end | |
end | |
introspection(CustomIntrospection) | |
class Thing < GraphQL::Schema::Object | |
field :name, String | |
end | |
class Query < GraphQL::Schema::Object | |
field :things, [Thing], null: true | |
def things | |
[ | |
{ name: "Pogo Stick" }, | |
{ name: "Immersion Blender" }, | |
{ name: "Ceiling Fan" }, | |
] | |
end | |
end | |
query(Query) | |
end | |
things_query_str = "{ things { name } }" | |
# Normal queries are permitted: | |
pp MySchema.execute(things_query_str, context: {}).to_h | |
# {"data"=> | |
# {"things"=> | |
# [{"name"=>"Pogo Stick"}, | |
# {"name"=>"Immersion Blender"}, | |
# {"name"=>"Ceiling Fan"}]}} | |
# But Introspection is not visible by default: | |
pp MySchema.execute(GraphQL::Introspection::INTROSPECTION_QUERY, context: {}).to_h | |
# {"errors"=> | |
# [{"message"=>"Field '__schema' doesn't exist on type 'Query'", | |
# ... | |
# Introspection can be permitted by a context flag: | |
pp MySchema.execute(GraphQL::Introspection::INTROSPECTION_QUERY, context: { introspection_permitted: true }).to_h | |
# {"code"=>"useAndDefineFragment", "fragmentName"=>"FullType"}}]} | |
# {"data"=> | |
# {"__schema"=> | |
# {"queryType"=>{"name"=>"Query"}, | |
# "mutationType"=>nil, | |
# "subscriptionType"=>nil, | |
# "types"=> # ... | |
# Mixed introspection and query also requires that context flag: | |
mixed_query_str = "{ things { name __typename } }" | |
# It's not visible without the flag: | |
pp MySchema.execute(mixed_query_str, context: {}).to_h | |
# {"errors"=> | |
# [{"message"=>"Field '__typename' doesn't exist on type 'Thing'", | |
# # ... | |
# But it _is_ permitted if the flag is present: | |
pp MySchema.execute(mixed_query_str, context: { introspection_permitted: true }).to_h | |
# {"data"=> | |
# {"things"=> | |
# [{"name"=>"Pogo Stick", "__typename"=>"Thing"}, | |
# {"name"=>"Immersion Blender", "__typename"=>"Thing"}, | |
# {"name"=>"Ceiling Fan", "__typename"=>"Thing"}]}} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment