Module: WCC::Contentful::Graphql::Federation

Extended by:
Federation
Included in:
Federation
Defined in:
lib/wcc/contentful/graphql/federation.rb,
lib/wcc/contentful/graphql/federation/builds_arguments.rb

Overview

Extend this module inside a root query definition to do schema federation. blog.apollographql.com/apollo-federation-f260cf525d21

This handles only queries, not mutations or subscriptions.

Defined Under Namespace

Classes: BuildsArguments, NamespacesTypes

Instance Method Summary collapse

Instance Method Details

#delegate_to_schema(schema, field_name: nil, arguments: nil) ⇒ Object



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/wcc/contentful/graphql/federation.rb', line 51

def delegate_to_schema(schema, field_name: nil, arguments: nil)
  ->(obj, inner_args, context) {
    field_name ||= context.ast_node.name

    arguments = arguments.call(obj, inner_args, context) if arguments&.respond_to?(:call)
    arguments = BuildsArguments.call(arguments) if arguments
    arguments ||= context.ast_node.arguments

    field_node = GraphQL::Language::Nodes::Field.new(
      name: field_name,
      arguments: arguments,
      selections: context.ast_node.selections,
      directives: context.ast_node.directives
    )

    query_node = GraphQL::Language::Nodes::OperationDefinition.new(
      name: context.query.operation_name,
      operation_type: 'query',
      variables: context.query.selected_operation.variables,
      selections: [
        field_node
      ]
    )

    # the ast_node.to_query_string prints the relevant section of the query to
    # a string.  We build a query out of that which we execute on the external
    # schema.
    query = query_node.to_query_string

    result = schema.execute(query,
      variables: context.query.variables)

    if result['errors'].present?
      raise GraphQL::ExecutionError.new(
        result.dig('errors', 0, 'message'),
        ast_node: context.ast_node
      )
    end

    result.dig('data', field_name)
  }
end

#schema_stitch(schema, namespace: nil) ⇒ Object

Accepts an externally defined schema with a root query, and “stitches” it’s query root into the current GraphQL::ObjectType definition. All fields on the external query object like ‘resource()`, `allResource()` will be inserted into the current object. The `resolve` method for those fields will execute a query on the external schema, returning the results.



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/wcc/contentful/graphql/federation.rb', line 15

def schema_stitch(schema, namespace: nil)
  ns_titleized = namespace&.titleize
  ns = NamespacesTypes.new(namespace: ns_titleized)

  def_fields =
    proc {
      schema.query.fields.each do |(key, field_def)|
        field key, ns.namespaced(field_def.type) do
          description field_def.description

          field_def.arguments.each do |(arg_name, arg)|
            argument arg_name, ns.namespaced(arg.type)
          end

          resolve delegate_to_schema(schema)
        end
      end
    }

  if namespace
    stub_class = Struct.new(:name)
    namespaced_type =
      GraphQL::ObjectType.define do
        name ns_titleized

        instance_exec(&def_fields)
      end

    field namespace, namespaced_type do
      resolve ->(_obj, _arguments, _context) { stub_class.new(namespace) }
    end
  else
    def_fields.call
  end
end