Class: GraphQL::Stitching::Request

Inherits:
Object
  • Object
show all
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

Instance Method Summary collapse

Constructor Details

#initialize(supergraph, source, operation_name: nil, variables: nil, context: nil) ⇒ Request

Creates a new supergraph request.

Parameters:

  • supergraph (Supergraph)

    supergraph instance that resolves the request.

  • source (String, GraphQL::Language::Nodes::Document)

    the request string or parsed AST.

  • operation_name (String, nil) (defaults to: nil)

    operation name selected for the request.

  • variables (Hash, nil) (defaults to: nil)

    input variables for the request.

  • context (Hash, nil) (defaults to: nil)

    a contextual object passed through resolver flows.



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/graphql/stitching/request.rb', line 29

def initialize(supergraph, source, operation_name: nil, variables: nil, context: nil)
  @supergraph = supergraph
  @prepared_document = nil
  @string = nil
  @digest = nil
  @normalized_string = nil
  @normalized_digest = nil
  @operation = nil
  @operation_directives = nil
  @variable_definitions = nil
  @fragment_definitions = nil
  @plan = nil

  params = {
    operation_name: operation_name,
    variables: variables,
    context: context,
  }

  if source.is_a?(String)
    @string = source
    params[:query] = source
  else
    params[:document] = source
  end

  @query = GraphQL::Query.new(@supergraph.schema, **params)
  @context = @query.context
  @context[:request] = self
end

Instance Attribute Details

#contextHash (readonly)

Returns contextual object passed through resolver flows.

Returns:

  • (Hash)

    contextual object passed through resolver flows.



21
22
23
# File 'lib/graphql/stitching/request.rb', line 21

def context
  @context
end

#queryGraphQL::Query (readonly)

Returns query object defining the request.

Returns:

  • (GraphQL::Query)

    query object defining the request.



18
19
20
# File 'lib/graphql/stitching/request.rb', line 18

def query
  @query
end

#supergraphSupergraph (readonly)

Returns supergraph instance that resolves the request.

Returns:

  • (Supergraph)

    supergraph instance that resolves the request.



15
16
17
# File 'lib/graphql/stitching/request.rb', line 15

def supergraph
  @supergraph
end

Instance Method Details

#digestString

Returns a digest of the original document string. Generally faster but less consistent.

Returns:

  • (String)

    a digest of the original document string. Generally faster but less consistent.



71
72
73
# File 'lib/graphql/stitching/request.rb', line 71

def digest
  @digest ||= Stitching.digest.call("#{Stitching::VERSION}/#{string}")
end

#execute(raw: false) ⇒ Hash

Executes the request and returns the rendered response.

Parameters:

  • raw (Boolean) (defaults to: false)

    specifies the result should be unshaped without pruning or null bubbling. Useful for debugging.

Returns:

  • (Hash)

    the rendered GraphQL response with "data" and "errors" sections.



171
172
173
174
# File 'lib/graphql/stitching/request.rb', line 171

def execute(raw: false)
  add_subscription_update_handler if subscription?
  Executor.new(self).perform(raw: raw)
end

#fragment_definitionsHash<String, GraphQL::Language::Nodes::FragmentDefinition>

Returns map of fragment names to their AST definitions.

Returns:

  • (Hash<String, GraphQL::Language::Nodes::FragmentDefinition>)

    map of fragment names to their AST definitions.



134
135
136
137
138
# File 'lib/graphql/stitching/request.rb', line 134

def fragment_definitions
  @fragment_definitions ||= prepared_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.

Returns:

  • (Boolean)

    true if operation type is a mutation



112
113
114
# File 'lib/graphql/stitching/request.rb', line 112

def mutation?
  @query.mutation?
end

#normalized_digestString

Returns a digest of the normalized document string. Slower but more consistent.

Returns:

  • (String)

    a digest of the normalized document string. Slower but more consistent.



76
77
78
# File 'lib/graphql/stitching/request.rb', line 76

def normalized_digest
  @normalized_digest ||= Stitching.digest.call("#{Stitching::VERSION}/#{normalized_string}")
end

#normalized_stringString

Returns a print of the parsed AST document with consistent whitespace.

Returns:

  • (String)

    a print of the parsed AST document with consistent whitespace.



66
67
68
# File 'lib/graphql/stitching/request.rb', line 66

def normalized_string
  @normalized_string ||= prepared_document.to_query_string
end

#operationGraphQL::Language::Nodes::OperationDefinition

Returns The selected root operation for the request.

Returns:

  • (GraphQL::Language::Nodes::OperationDefinition)

    The selected root operation for the request.



81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/graphql/stitching/request.rb', line 81

def operation
  @operation ||= with_prepared_document do
    selected_op = @query.selected_operation
    raise GraphQL::ExecutionError, "No operation selected" unless selected_op

    @prepared_document.definitions.find do |d|
      next unless d.is_a?(GraphQL::Language::Nodes::OperationDefinition)

      selected_op.name.nil? || d.name == selected_op.name
    end
  end
end

#operation_directivesString

Returns A string of directives applied to the root operation. These are passed through in all subgraph requests.

Returns:

  • (String)

    A string of directives applied to the root operation. These are passed through in all subgraph requests.



99
100
101
102
103
104
# File 'lib/graphql/stitching/request.rb', line 99

def operation_directives
  @operation_directives ||= if operation.directives.any?
    printer = GraphQL::Language::Printer.new
    operation.directives.map { printer.print(_1) }.join(" ")
  end
end

#operation_nameObject



94
95
96
# File 'lib/graphql/stitching/request.rb', line 94

def operation_name
  operation.name
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

Parameters:

  • new_plan (Plan, nil) (defaults to: nil)

    a cached query plan for the request.

Returns:

  • (Plan)

    query plan for the request.



159
160
161
162
163
164
165
166
# File 'lib/graphql/stitching/request.rb', line 159

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

#query?Boolean

Returns true if operation type is a query.

Returns:

  • (Boolean)

    true if operation type is a query



107
108
109
# File 'lib/graphql/stitching/request.rb', line 107

def query?
  @query.query?
end

#stringString

Returns the original document string, or a print of the parsed AST document.

Returns:

  • (String)

    the original document string, or a print of the parsed AST document.



61
62
63
# File 'lib/graphql/stitching/request.rb', line 61

def string
  with_prepared_document { @string || normalized_string }
end

#subscription?Boolean

Returns true if operation type is a subscription.

Returns:

  • (Boolean)

    true if operation type is a subscription



117
118
119
# File 'lib/graphql/stitching/request.rb', line 117

def subscription?
  @query.subscription?
end

#validateArray<GraphQL::ExecutionError>

Validates the request using the combined supergraph schema.

Returns:

  • (Array<GraphQL::ExecutionError>)

    an array of static validation errors



142
143
144
# File 'lib/graphql/stitching/request.rb', line 142

def validate
  @query.static_errors
end

#variable_definitionsHash<String, GraphQL::Language::Nodes::AbstractNode>

Returns map of variable names to AST type definitions.

Returns:

  • (Hash<String, GraphQL::Language::Nodes::AbstractNode>)

    map of variable names to AST type definitions.



127
128
129
130
131
# File 'lib/graphql/stitching/request.rb', line 127

def variable_definitions
  @variable_definitions ||= operation.variables.each_with_object({}) do |v, memo|
    memo[v.name] = v.type
  end
end

#variablesHash<String, Any>

Returns provided variables hash filled in with default values from definitions.

Returns:

  • (Hash<String, Any>)

    provided variables hash filled in with default values from definitions



122
123
124
# File 'lib/graphql/stitching/request.rb', line 122

def variables
  @variables || with_prepared_document { @variables }
end