Class: GraphQL::Stitching::Request
- Inherits:
-
Object
- Object
- GraphQL::Stitching::Request
- Defined in:
- lib/graphql/stitching/request.rb,
lib/graphql/stitching/request/skip_include.rb
Overview
Request combines a supergraph, GraphQL document, variables, variable/fragment definitions, and the selected operation. It provides the lifecycle of validating, preparing, planning, and executing upon these inputs.
Defined Under Namespace
Classes: SkipInclude
Constant Summary collapse
- SKIP_INCLUDE_DIRECTIVE =
/@(?:skip|include)/
Instance Attribute Summary collapse
-
#context ⇒ Hash
readonly
Contextual object passed through resolver flows.
-
#document ⇒ GraphQL::Language::Nodes::Document
readonly
The parsed GraphQL AST document.
-
#operation_name ⇒ String
readonly
Operation name selected for the request.
-
#supergraph ⇒ Supergraph
readonly
Supergraph instance that resolves the request.
-
#variables ⇒ Hash
readonly
Input variables for the request.
-
#warden ⇒ GraphQL::Schema::Warden
readonly
A visibility warden for this request.
Instance Method Summary collapse
-
#digest ⇒ String
A digest of the original document string.
-
#execute(raw: false) ⇒ Hash
Executes the request and returns the rendered response.
-
#fragment_definitions ⇒ Hash<String, GraphQL::Language::Nodes::FragmentDefinition>
Map of fragment names to their AST definitions.
-
#initialize(supergraph, document, operation_name: nil, variables: nil, context: nil) ⇒ Request
constructor
Creates a new supergraph request.
-
#mutation? ⇒ Boolean
True if operation type is a mutation.
-
#normalized_digest ⇒ String
A digest of the normalized document string.
-
#normalized_string ⇒ String
A print of the parsed AST document with consistent whitespace.
-
#operation ⇒ GraphQL::Language::Nodes::OperationDefinition
The selected root operation for the request.
-
#operation_directives ⇒ String
A string of directives applied to the root operation.
-
#plan(new_plan = nil) ⇒ Plan
Gets and sets the query plan for the request.
-
#prepare! ⇒ Object
Prepares the request for stitching by inserting variable defaults and applying @skip/@include conditionals.
-
#query? ⇒ Boolean
True if operation type is a query.
-
#string ⇒ String
The original document string, or a print of the parsed AST document.
-
#subscription? ⇒ Boolean
True if operation type is a subscription.
-
#validate ⇒ Array<GraphQL::ExecutionError>
Validates the request using the combined supergraph schema.
-
#variable_definitions ⇒ Hash<String, GraphQL::Language::Nodes::AbstractNode>
Map of variable names to AST type definitions.
Constructor Details
#initialize(supergraph, document, operation_name: nil, variables: nil, context: nil) ⇒ Request
Creates a new supergraph request.
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/graphql/stitching/request.rb', line 38 def initialize(supergraph, document, operation_name: nil, variables: nil, context: nil) @supergraph = supergraph @string = nil @digest = nil @normalized_string = nil @normalized_digest = nil @operation = nil @operation_directives = nil @variable_definitions = nil @fragment_definitions = nil @plan = nil @document = if document.is_a?(String) @string = document GraphQL.parse(document) else document end @operation_name = operation_name @variables = variables || {} @query = GraphQL::Query.new(@supergraph.schema, document: @document, context: context) @warden = @query.warden @context = @query.context @context[:request] = self end |
Instance Attribute Details
#context ⇒ Hash (readonly)
Returns contextual object passed through resolver flows.
27 28 29 |
# File 'lib/graphql/stitching/request.rb', line 27 def context @context end |
#document ⇒ GraphQL::Language::Nodes::Document (readonly)
Returns the parsed GraphQL AST document.
18 19 20 |
# File 'lib/graphql/stitching/request.rb', line 18 def document @document end |
#operation_name ⇒ String (readonly)
Returns operation name selected for the request.
24 25 26 |
# File 'lib/graphql/stitching/request.rb', line 24 def operation_name @operation_name end |
#supergraph ⇒ Supergraph (readonly)
Returns supergraph instance that resolves the request.
15 16 17 |
# File 'lib/graphql/stitching/request.rb', line 15 def supergraph @supergraph end |
#variables ⇒ Hash (readonly)
Returns input variables for the request.
21 22 23 |
# File 'lib/graphql/stitching/request.rb', line 21 def variables @variables end |
#warden ⇒ GraphQL::Schema::Warden (readonly)
Returns a visibility warden for this request.
30 31 32 |
# File 'lib/graphql/stitching/request.rb', line 30 def warden @warden end |
Instance Method Details
#digest ⇒ String
Returns a digest of the original document string. Generally faster but less consistent.
77 78 79 |
# File 'lib/graphql/stitching/request.rb', line 77 def digest @digest ||= Stitching.digest.call("#{Stitching::VERSION}/#{string}") end |
#execute(raw: false) ⇒ Hash
Executes the request and returns the rendered response.
191 192 193 194 |
# File 'lib/graphql/stitching/request.rb', line 191 def execute(raw: false) add_subscription_update_handler if subscription? Executor.new(self).perform(raw: raw) end |
#fragment_definitions ⇒ Hash<String, GraphQL::Language::Nodes::FragmentDefinition>
Returns map of fragment names to their AST definitions.
135 136 137 138 139 |
# File 'lib/graphql/stitching/request.rb', line 135 def fragment_definitions @fragment_definitions ||= @document.definitions.each_with_object({}) do |d, memo| memo[d.name] = d if d.is_a?(GraphQL::Language::Nodes::FragmentDefinition) end end |
#mutation? ⇒ Boolean
Returns true if operation type is a mutation.
110 111 112 |
# File 'lib/graphql/stitching/request.rb', line 110 def mutation? operation.operation_type == MUTATION_OP end |
#normalized_digest ⇒ String
Returns a digest of the normalized document string. Slower but more consistent.
82 83 84 |
# File 'lib/graphql/stitching/request.rb', line 82 def normalized_digest @normalized_digest ||= Stitching.digest.call("#{Stitching::VERSION}/#{normalized_string}") end |
#normalized_string ⇒ String
Returns a print of the parsed AST document with consistent whitespace.
72 73 74 |
# File 'lib/graphql/stitching/request.rb', line 72 def normalized_string @normalized_string ||= @document.to_query_string end |
#operation ⇒ GraphQL::Language::Nodes::OperationDefinition
Returns The selected root operation for the request.
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/graphql/stitching/request.rb', line 87 def operation @operation ||= begin operation_defs = @document.definitions.select do |d| next unless d.is_a?(GraphQL::Language::Nodes::OperationDefinition) @operation_name ? d.name == @operation_name : true end if operation_defs.length < 1 raise GraphQL::ExecutionError, "Invalid root operation for given name and operation type." elsif operation_defs.length > 1 raise GraphQL::ExecutionError, "An operation name is required when sending multiple operations." end operation_defs.first end end |
#operation_directives ⇒ String
Returns A string of directives applied to the root operation. These are passed through in all subgraph requests.
120 121 122 123 124 125 |
# File 'lib/graphql/stitching/request.rb', line 120 def operation_directives @operation_directives ||= if operation.directives.any? printer = GraphQL::Language::Printer.new operation.directives.map { printer.print(_1) }.join(" ") end end |
#plan(new_plan = nil) ⇒ Plan
Gets and sets the query plan for the request. Assigned query plans may pull from a cache, which is useful for redundant GraphQL documents (commonly sent by frontend clients).
if cached_plan = $cache.get(request.digest)
plan = GraphQL::Stitching::Plan.from_json(JSON.parse(cached_plan))
request.plan(plan)
else
plan = request.plan
$cache.set(request.digest, JSON.generate(plan.as_json))
end
179 180 181 182 183 184 185 186 |
# File 'lib/graphql/stitching/request.rb', line 179 def plan(new_plan = nil) if new_plan raise StitchingError, "Plan must be a `GraphQL::Stitching::Plan`." unless new_plan.is_a?(Plan) @plan = new_plan else @plan ||= Planner.new(self).perform end end |
#prepare! ⇒ Object
Prepares the request for stitching by inserting variable defaults and applying @skip/@include conditionals.
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/graphql/stitching/request.rb', line 149 def prepare! operation.variables.each do |v| @variables[v.name] = v.default_value if @variables[v.name].nil? && !v.default_value.nil? end if @string.nil? || @string.match?(SKIP_INCLUDE_DIRECTIVE) SkipInclude.render(@document, @variables) do |modified_ast| @document = modified_ast @string = @normalized_string = nil @digest = @normalized_digest = nil @operation = @operation_directives = @variable_definitions = @plan = nil end end self end |
#query? ⇒ Boolean
Returns true if operation type is a query.
105 106 107 |
# File 'lib/graphql/stitching/request.rb', line 105 def query? operation.operation_type == QUERY_OP end |
#string ⇒ String
Returns the original document string, or a print of the parsed AST document.
67 68 69 |
# File 'lib/graphql/stitching/request.rb', line 67 def string @string || normalized_string end |
#subscription? ⇒ Boolean
Returns true if operation type is a subscription.
115 116 117 |
# File 'lib/graphql/stitching/request.rb', line 115 def subscription? operation.operation_type == SUBSCRIPTION_OP end |
#validate ⇒ Array<GraphQL::ExecutionError>
Validates the request using the combined supergraph schema.
143 144 145 146 |
# File 'lib/graphql/stitching/request.rb', line 143 def validate result = @supergraph.static_validator.validate(@query) result[:errors] end |
#variable_definitions ⇒ Hash<String, GraphQL::Language::Nodes::AbstractNode>
Returns map of variable names to AST type definitions.
128 129 130 131 132 |
# File 'lib/graphql/stitching/request.rb', line 128 def variable_definitions @variable_definitions ||= operation.variables.each_with_object({}) do |v, memo| memo[v.name] = v.type end end |