Module: Rails::GraphQL

Extended by:
ActiveSupport::Autoload
Includes:
ActiveSupport::Configurable
Defined in:
lib/rails/graphql.rb,
lib/rails/graphql/type.rb,
lib/rails/graphql/event.rb,
lib/rails/graphql/field.rb,
lib/rails/graphql/config.rb,
lib/rails/graphql/errors.rb,
lib/rails/graphql/schema.rb,
lib/rails/graphql/source.rb,
lib/rails/graphql/to_gql.rb,
lib/rails/graphql/helpers.rb,
lib/rails/graphql/railtie.rb,
lib/rails/graphql/request.rb,
lib/rails/graphql/version.rb,
lib/rails/graphql/argument.rb,
lib/rails/graphql/callback.rb,
lib/rails/graphql/type_map.rb,
lib/rails/graphql/directive.rb,
lib/rails/graphql/global_id.rb,
lib/rails/graphql/type/enum.rb,
lib/rails/graphql/collectors.rb,
lib/rails/graphql/type/input.rb,
lib/rails/graphql/type/union.rb,
lib/rails/graphql/alternative.rb,
lib/rails/graphql/source/base.rb,
lib/rails/graphql/type/object.rb,
lib/rails/graphql/type/scalar.rb,
lib/rails/graphql/subscription.rb,
lib/rails/graphql/type/creator.rb,
lib/rails/graphql/introspection.rb,
lib/rails/graphql/request/event.rb,
lib/rails/graphql/request/errors.rb,
lib/rails/graphql/source/builder.rb,
lib/rails/graphql/type/interface.rb,
lib/rails/graphql/request/context.rb,
lib/rails/graphql/railties/channel.rb,
lib/rails/graphql/request/strategy.rb,
lib/rails/graphql/alternative/query.rb,
lib/rails/graphql/field/input_field.rb,
lib/rails/graphql/field/typed_field.rb,
lib/rails/graphql/helpers/with_name.rb,
lib/rails/graphql/request/arguments.rb,
lib/rails/graphql/request/backtrace.rb,
lib/rails/graphql/request/component.rb,
lib/rails/graphql/field/output_field.rb,
lib/rails/graphql/helpers/with_owner.rb,
lib/rails/graphql/subscription/store.rb,
lib/rails/graphql/adapters/pg_adapter.rb,
lib/rails/graphql/field/proxied_field.rb,
lib/rails/graphql/field/scoped_config.rb,
lib/rails/graphql/helpers/with_events.rb,
lib/rails/graphql/helpers/with_fields.rb,
lib/rails/graphql/railties/controller.rb,
lib/rails/graphql/alternative/mutation.rb,
lib/rails/graphql/field/mutation_field.rb,
lib/rails/graphql/field/resolved_field.rb,
lib/rails/graphql/helpers/instantiable.rb,
lib/rails/graphql/helpers/leaf_from_ar.rb,
lib/rails/graphql/helpers/registerable.rb,
lib/rails/graphql/request/subscription.rb,
lib/rails/graphql/alternative/field_set.rb,
lib/rails/graphql/request/prepared_data.rb,
lib/rails/graphql/subscription/provider.rb,
lib/rails/graphql/type/scalar/id_scalar.rb,
lib/rails/graphql/adapters/mysql_adapter.rb,
lib/rails/graphql/field/authorized_field.rb,
lib/rails/graphql/helpers/unregisterable.rb,
lib/rails/graphql/helpers/with_arguments.rb,
lib/rails/graphql/helpers/with_callbacks.rb,
lib/rails/graphql/helpers/with_global_id.rb,
lib/rails/graphql/helpers/with_namespace.rb,
lib/rails/graphql/helpers/with_validator.rb,
lib/rails/graphql/type/scalar/any_scalar.rb,
lib/rails/graphql/type/scalar/int_scalar.rb,
lib/rails/graphql/adapters/sqlite_adapter.rb,
lib/rails/graphql/helpers/with_assignment.rb,
lib/rails/graphql/helpers/with_directives.rb,
lib/rails/graphql/railties/base_generator.rb,
lib/rails/graphql/railties/log_subscriber.rb,
lib/rails/graphql/request/component/field.rb,
lib/rails/graphql/source/scoped_arguments.rb,
lib/rails/graphql/subscription/store/base.rb,
lib/rails/graphql/type/object/type_object.rb,
lib/rails/graphql/type/scalar/date_scalar.rb,
lib/rails/graphql/type/scalar/json_scalar.rb,
lib/rails/graphql/type/scalar/time_scalar.rb,
lib/rails/graphql/alternative/subscription.rb,
lib/rails/graphql/directive/skip_directive.rb,
lib/rails/graphql/field/subscription_field.rb,
lib/rails/graphql/helpers/with_description.rb,
lib/rails/graphql/request/component/spread.rb,
lib/rails/graphql/request/steps/preparable.rb,
lib/rails/graphql/request/steps/resolvable.rb,
lib/rails/graphql/type/enum/type_kind_enum.rb,
lib/rails/graphql/type/object/field_object.rb,
lib/rails/graphql/type/scalar/float_scalar.rb,
lib/rails/graphql/collectors/hash_collector.rb,
lib/rails/graphql/collectors/json_collector.rb,
lib/rails/graphql/request/steps/organizable.rb,
lib/rails/graphql/subscription/store/memory.rb,
lib/rails/graphql/type/object/schema_object.rb,
lib/rails/graphql/type/scalar/bigint_scalar.rb,
lib/rails/graphql/type/scalar/binary_scalar.rb,
lib/rails/graphql/type/scalar/string_scalar.rb,
lib/rails/graphql/directive/cached_directive.rb,
lib/rails/graphql/helpers/with_schema_fields.rb,
lib/rails/graphql/request/component/fragment.rb,
lib/rails/graphql/request/component/typename.rb,
lib/rails/graphql/request/helpers/directives.rb,
lib/rails/graphql/request/steps/authorizable.rb,
lib/rails/graphql/subscription/provider/base.rb,
lib/rails/graphql/type/scalar/boolean_scalar.rb,
lib/rails/graphql/type/scalar/decimal_scalar.rb,
lib/rails/graphql/directive/include_directive.rb,
lib/rails/graphql/helpers/attribute_delegator.rb,
lib/rails/graphql/railties/controller_runtime.rb,
lib/rails/graphql/request/component/operation.rb,
lib/rails/graphql/source/active_record_source.rb,
lib/rails/graphql/collectors/idented_collector.rb,
lib/rails/graphql/helpers/inherited_collection.rb,
lib/rails/graphql/type/object/directive_object.rb,
lib/rails/graphql/type/scalar/date_time_scalar.rb,
lib/rails/graphql/request/helpers/selection_set.rb,
lib/rails/graphql/request/helpers/value_writers.rb,
lib/rails/graphql/source/active_record/builders.rb,
lib/rails/graphql/type/object/enum_value_object.rb,
lib/rails/graphql/directive/deprecated_directive.rb,
lib/rails/graphql/type/object/input_value_object.rb,
lib/rails/graphql/directive/specified_by_directive.rb,
lib/rails/graphql/request/strategy/cached_strategy.rb,
lib/rails/graphql/helpers/inherited_collection/base.rb,
lib/rails/graphql/helpers/inherited_collection/hash.rb,
lib/rails/graphql/request/strategy/dynamic_instance.rb,
lib/rails/graphql/type/enum/directive_location_enum.rb,
lib/rails/graphql/helpers/inherited_collection/array.rb,
lib/rails/graphql/subscription/provider/action_cable.rb,
lib/rails/graphql/request/strategy/sequenced_strategy.rb,
lib/rails/graphql/request/strategy/multi_query_strategy.rb,
lib/rails/graphql/request/component/operation/subscription.rb

Overview

Rails GraphQL

This implementation tries to be as close as the GraphQL spec as possible, meaning that this lib shares most of the same names and directions provided by the GraphQL spec. You can use Rails::GraphQL::SPEC_VERSION to check which spec is being sued.

Using ActiveSupport, define all the needed objects but doesn’t load them since it’s better to trust on eager_load in order to proper load the objects.

A very important concept is that Singleton definitions are a direct connection to a GraphQL Introspection, meaning that to query the introspection is to query everything defined and associated with the GraphQL objects, the only exception are arguments, directives and fields:

  • Arguments: They are strictly associated with the object that defined it, also arguments with the same name doesn’t mean they have the same behavior or configuration.

  • Directives: A directive definition belongs to the introspection and is handled in the Singleton extent. They are handled as instance whenever a definition or an execution uses them.

  • Fields: Many other types and helper containers holds a series of fields, which means that fields with the same name will probably behave differently.

Defined Under Namespace

Modules: Alternative, BaseGenerator, Channel, Collectors, Controller, ControllerRuntime, Helpers, Introspection, MySQL, PG, SQLite, Subscription, VERSION Classes: Argument, CacheKey, Callback, Directive, Event, Field, GlobalID, LogSubscriber, Railtie, Request, Schema, Source, ToGQL, Type, TypeMap

Constant Summary collapse

SPEC_VERSION =

Stores the version of the GraphQL spec used for this implementation

::GQLParser::VERSION
EMPTY_ARRAY =

Just a reusable instances of an empty array and empty hash

[].freeze
EMPTY_HASH =
{}.freeze
RuntimeRegistry =

Runtime registry for request execution time

Class.new { thread_mattr_accessor :gql_runtime }
AR710 =
(ActiveRecord.gem_version >= Gem::Version.new('7.1.0'))
StandardError =

Error class tha wraps all the other error classes

Class.new(::StandardError)
DefinitionError =

Error class related to problems during the definition process

Class.new(StandardError)
ValidationError =

Error class related to validation of a value

Class.new(StandardError)
ArgumentError =

Errors that can happen related to the arguments given to a method

Class.new(DefinitionError)
NotFoundError =

Errors that can happen when locking for definition objects, like fields

Class.new(DefinitionError)
NameError =

Errors related to the name of the objects

Class.new(DefinitionError)
DuplicatedError =

Errors related to duplicated objects

Class.new(NameError)
ExecutionError =

Error class related to problems during the execution process

Class.new(StandardError)
ParseError =

Error related to the parsing process

Class.new(ExecutionError)
ArgumentsError =

Error class related to parsing the arguments

Class.new(ParseError)
FieldError =

Error class related to problems that happened during execution of fields

Class.new(ExecutionError)
MissingFieldError =

Error class related to when a field was not found on the requested object

Class.new(FieldError)
DisabledFieldError =

Error class related to when a field was found but is marked as disabled

Class.new(FieldError)
InvalidValueError =

Error class related to when the captured output value is invalid due to type checking

Class.new(FieldError)
UnauthorizedFieldError =

Error class related to when a field is unauthorized and can not be used, similar to disabled fields

Class.new(FieldError)
SubscriptionError =

Error class related to problems that happened while subscribing to a field

Class.new(FieldError)
StaticResponse =

Error class related to execution responses that don’t require processing

Class.new(Interrupt)
CachedResponse =

Error class related to cached responses, which doesn’t need processing

Class.new(StaticResponse)
PersistedQueryNotFound =

Error class related to a persisted query that has’t been persisted yet

Class.new(StaticResponse)
ExtendedError =

A simple module and way to extend errors with extra information

Module.new do
  delegate_missing_to :@extension

  def self.extend(error, extension)
    error.instance_variable_set(:@extension, extension)
    error.extend(self)
    error
  end
end

Class Method Summary collapse

Class Method Details

.add_dependencies(type, *list, to: :base) ⇒ Object

Load a given list of dependencies from the given type

Raises:



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/rails/graphql.rb', line 146

def add_dependencies(type, *list, to: :base)
  ref = config.known_dependencies

  raise ArgumentError, (+<<~MSG).squish if (ref = ref[type]).nil?
    There are no #{type} known dependencies.
  MSG

  list = list.flatten.compact.map do |item|
    next item unless (item = ref[item]).nil?
    raise ArgumentError, (+<<~MSG).squish
      Unable to find #{item} as #{type} in known dependencies.
    MSG
  end

  type_map.add_dependencies(list, to: to)
end

.ar_adapter_key(adapter_name) ⇒ Object

Find the key associated with the given adapter_name



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

def ar_adapter_key(adapter_name)
  config.ar_adapters.dig(adapter_name, :key)
end

.directives_to_set(list, others = nil, event = nil, **xargs) ⇒ Object

Returns a set instance with uniq directives from the given list. If the same directive class is given twice, it will raise an exception, since they must be uniq within a list of directives.

Use the others argument to provide a list of already defined directives so the check can be performed using a inherited_collection.

If a source is provided, then an :attach event will be triggered for each directive on the given source element.



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/rails/graphql.rb', line 172

def directives_to_set(list, others = nil, event = nil, **xargs)
  return if list.blank?

  if (source = xargs.delete(:source)).present?
    location = xargs.delete(:location) || source.try(:directive_location)
    event ||= GraphQL::Event.new(:attach, source, phase: :definition, **xargs)
  end

  others = others&.to_set
  enumerate(list).each_with_object(Set.new) do |item, result|
    raise ArgumentError, (+<<~MSG).squish unless item.kind_of?(GraphQL::Directive)
      The "#{item.class}" is not a valid directive.
    MSG

    check_location = location.present? && !item.locations.include?(location)
    raise ArgumentError, (+<<~MSG).squish if check_location
      You cannot use @#{item.gql_name} directive due to location restriction.
    MSG

    check_uniqueness = !item.repeatable? && (others&.any?(item) || result.any?(item))
    raise DuplicatedError, (+<<~MSG).squish if check_uniqueness
      A @#{item.gql_name} directive have already been provided.
    MSG

    unless event.nil?
      begin
        item.assign_owner!(event.source)
        event.trigger_object(item)
        item.validate!
      rescue => error
        raise StandardError, (+<<~MSG).squish
          Unable to #{event.event_name} the @#{item.gql_name} directive: #{error.message}
        MSG
      end
    end

    result << item
  end
end

.enable_ar_adapter(adapter_name) ⇒ Object

This is a little helper to require ActiveRecord adapter specific configurations

Raises:

  • (::ArgumentError)


113
114
115
116
117
118
119
120
121
122
# File 'lib/rails/graphql.rb', line 113

def enable_ar_adapter(adapter_name)
  return if (@@loaded_adapters ||= Set.new).include?(adapter_name)

  raise ::ArgumentError, (+<<~MSG).squish unless config.ar_adapters.key?(adapter_name)
    There is no GraphQL mapping for #{adapter_name} ActiveRecord adapter.
  MSG

  require(config.ar_adapters.dig(adapter_name, :path))
  @@loaded_adapters << adapter_name
end

.enumerate(value) ⇒ Object

A generic helper to not create a new array when just iterating over something that may or may not be an array



141
142
143
# File 'lib/rails/graphql.rb', line 141

def enumerate(value)
  (value.is_a?(Enumerable) || value.respond_to?(:to_ary)) ? value : value.then
end

.gem_versionObject

Returns the currently loaded version of the GraphQL as a Gem::Version.



6
7
8
# File 'lib/rails/graphql/version.rb', line 6

def self.gem_version
  Gem::Version.new(version)
end

.loggerObject

This is the logger for all the operations for GraphQL



206
207
208
# File 'lib/rails/graphql/config.rb', line 206

def self.logger
  config.logger ||= ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDOUT))
end

.reload_ar_adapters!Object

Due to reloader process, adapter settings need to be reloaded



125
126
127
128
129
# File 'lib/rails/graphql.rb', line 125

def reload_ar_adapters!
  return unless defined?(@@loaded_adapters)
  adapters, @@loaded_adapters = @@loaded_adapters, Set.new
  adapters.map(&method(:enable_ar_adapter))
end

.to_gql(object, **xargs) ⇒ Object Also known as: to_graphql

Turn the given object into its string representation as GraphQl See ToGQL class.



133
134
135
# File 'lib/rails/graphql.rb', line 133

def to_gql(object, **xargs)
  ToGQL.compile(object, **xargs)
end

.type_mapObject

Access to the type mapper



102
103
104
# File 'lib/rails/graphql.rb', line 102

def type_map
  @@type_map ||= GraphQL::TypeMap.new
end

.versionObject



10
11
12
# File 'lib/rails/graphql/version.rb', line 10

def self.version
  VERSION::STRING
end