Last active
December 8, 2021 16:13
-
-
Save rmosolgo/32513b1075c99a6216604ea0449fa1ca to your computer and use it in GitHub Desktop.
Preventing access to nested lists in 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", "1.12.20" | |
end | |
class PreventNestedCards < GraphQL::Analysis::AST::Analyzer | |
def initialize(query) | |
super | |
@inside_players_selection = false | |
end | |
def on_enter_field(node, parent, visitor) | |
if (field_defn = visitor.field_definition) | |
if field_defn.graphql_name == "players" | |
@inside_players_selection = true | |
elsif @inside_players_selection && field_defn.graphql_name == "cards" | |
raise GraphQL::AnalysisError.new( | |
"Selecting `cards` within a list of `players` is not supported; Select cards for a specific player instead.", | |
ast_node: node, | |
) | |
end | |
end | |
end | |
def on_leave_field(node, parent, visitor) | |
if @inside_players_selection && (field_defn = visitor.field_definition) && field_defn.graphql_name == "players" | |
@inside_players_selection = false | |
end | |
end | |
def result | |
nil # nothing required here, since the error is raised above if anything goes wrong | |
end | |
end | |
class Schema < GraphQL::Schema | |
class Card < GraphQL::Schema::Object | |
field :id, String, null: false | |
end | |
class Player < GraphQL::Schema::Object | |
field :id, String, null: false | |
field :name, String, null: false | |
field :cards, Card.connection_type, null: false | |
end | |
class Query < GraphQL::Schema::Object | |
field :players, Player.connection_type, null: true | |
field :player, Player, null: true do | |
argument :id, String, required: true | |
end | |
# I added this to demonstrate that other selections are allowed: | |
field :cards, Card.connection_type, null: true | |
end | |
query(Query) | |
query_analyzer(PreventNestedCards) | |
end | |
# Not permitted | |
pp Schema.execute("{ players { nodes { cards { nodes { id } } } } }").to_h | |
# {"errors"=> | |
# [{"message"=> | |
# "Selecting `cards` within a list of `players` is not supported; Select cards for a specific player instead.", | |
# "locations"=>[{"line"=>1, "column"=>21}]}]} | |
# Fragments not permitted, either | |
pp Schema.execute(<<-GRAPHQL).to_h | |
{ | |
players { ...Players } | |
__typename | |
} | |
fragment Players on PlayerConnection { | |
nodes { | |
cards { | |
nodes { id } | |
} | |
} | |
} | |
GRAPHQL | |
# {"errors"=> | |
# [{"message"=> | |
# "Selecting `cards` within a list of `players` is not supported; Select cards for a specific player instead.", | |
# "locations"=>[{"line"=>8, "column"=>5}]}]} | |
pp Schema.execute(<<-GRAPHQL).to_h | |
{ | |
players { nodes { ...Player } } | |
__typename | |
} | |
fragment Player on Player { | |
cards { | |
nodes { id } | |
} | |
} | |
GRAPHQL | |
# {"errors"=> | |
# [{"message"=> | |
# "Selecting `cards` within a list of `players` is not supported; Select cards for a specific player instead.", | |
# "locations"=>[{"line"=>7, "column"=>3}]}]} | |
# Inline Fragments: | |
pp Schema.execute(<<-GRAPHQL).to_h | |
{ | |
players { | |
nodes { | |
...on Player { | |
cards { nodes { id } } | |
} | |
} | |
} | |
__typename | |
} | |
GRAPHQL | |
# {"errors"=> | |
# [{"message"=> | |
# "Selecting `cards` within a list of `players` is not supported; Select cards for a specific player instead.", | |
# "locations"=>[{"line"=>5, "column"=>9}]}]} | |
# Permitted, although they return `nil` because this example has no data: | |
pp Schema.execute("{ player(id: \"abc\") { cards { nodes { id } } } }", root_value: {} ).to_h | |
# {"data"=>{"player"=>nil}} | |
pp Schema.execute("{ players { nodes { name } } cards { nodes { id } } }", root_value: {} ).to_h | |
# {"data"=>{"players"=>nil, "cards"=>nil}} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment