Module: GraphQL::Schema::Loader

Extended by:
Loader
Included in:
Loader
Defined in:
lib/graphql/schema/loader.rb

Overview

You can use the result of Introspection::INTROSPECTION_QUERY to make a schema. This schema is missing some important details like resolve functions, but it does include the full type system, so you can use it to validate queries.

See Also:

Constant Summary collapse

NullScalarCoerce =
->(val, _ctx) { val }

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.build_arguments(arg_owner, args, type_resolver) ⇒ Object

[View source]

197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/graphql/schema/loader.rb', line 197

def build_arguments(arg_owner, args, type_resolver)
  args.each do |arg|
    kwargs = {
      type: type_resolver.call(arg["type"]),
      description: arg["description"],
      deprecation_reason: arg["deprecationReason"],
      required: false,
      camelize: false,
    }

    if arg["defaultValue"]
      default_value_str = arg["defaultValue"]

      dummy_query_str = "query getStuff($var: InputObj = #{default_value_str}) { __typename }"

      # Returns a `GraphQL::Language::Nodes::Document`:
      dummy_query_ast = GraphQL.parse(dummy_query_str)

      # Reach into the AST for the default value:
      input_value_ast = dummy_query_ast.definitions.first.variables.first.default_value

      kwargs[:default_value] = extract_default_value(default_value_str, input_value_ast)
    end

    arg_owner.argument(arg["name"], **kwargs)
  end
end

.build_fields(type_defn, fields, type_resolver) ⇒ Object

[View source]

173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# File 'lib/graphql/schema/loader.rb', line 173

def build_fields(type_defn, fields, type_resolver)
  loader = self
  fields.each do |field_hash|
    unwrapped_field_hash = field_hash
    while (of_type = unwrapped_field_hash["ofType"])
      unwrapped_field_hash = of_type
    end

    type_defn.field(
      field_hash["name"],
      type: type_resolver.call(field_hash["type"]),
      description: field_hash["description"],
      deprecation_reason: field_hash["deprecationReason"],
      null: true,
      camelize: false,
      connection_extension: nil,
    ) do
      if field_hash["args"].any?
        loader.build_arguments(self, field_hash["args"], type_resolver)
      end
    end
  end
end

Instance Method Details

#load(introspection_result) ⇒ Class

Create schema with the result of an introspection query.

Parameters:

Returns:

  • (Class)

    the schema described by input

[View source]

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
50
51
52
# File 'lib/graphql/schema/loader.rb', line 16

def load(introspection_result)
  schema = introspection_result.fetch("data").fetch("__schema")

  types = {}
  type_resolver = ->(type) { resolve_type(types, type) }

  schema.fetch("types").each do |type|
    next if type.fetch("name").start_with?("__")
    type_object = define_type(type, type_resolver)
    types[type["name"]] = type_object
  end

  directives = []
  schema.fetch("directives", []).each do |directive|
    next if GraphQL::Schema.default_directives.include?(directive.fetch("name"))
    directives << define_directive(directive, type_resolver)
  end

  Class.new(GraphQL::Schema) do
    add_type_and_traverse(types.values, root: false)
    orphan_types(types.values.select { |t| t.kind.object? })
    directives(directives)
    description(schema["description"])

    def self.resolve_type(*)
      raise(GraphQL::RequiredImplementationMissingError, "This schema was loaded from string, so it can't resolve types for objects")
    end

    [:query, :mutation, :subscription].each do |root|
      type = schema["#{root}Type"]
      if type
        type_defn = types.fetch(type.fetch("name"))
        self.public_send(root, type_defn)
      end
    end
  end
end