diff --git a/guides/mutations/mutation_classes.md b/guides/mutations/mutation_classes.md index 1a43817527..3b9f93a02d 100644 --- a/guides/mutations/mutation_classes.md +++ b/guides/mutations/mutation_classes.md @@ -162,6 +162,10 @@ end In the above examples, `loads:` is provided a concrete type, but it also supports abstract types (i.e. interfaces and unions). +### Resolving the type of loaded objects + +When `loads:` gets an object from {{ "Schema.object_from_id" | api_doc }}, it passes that object to {{ "Schema.resolve_type" | api_doc }} to confirm that it resolves to the same type originally configured with `loads:`. + ### Handling failed loads If `loads:` fails to find an object or if the loaded object isn't resolved to the specified `loads:` type (using {{ "Schema.resolve_type" | api_doc }}), a {{ "GraphQL::LoadApplicationObjectFailedError" | api_doc }} is raised and returned to the client. diff --git a/guides/schema/definition.md b/guides/schema/definition.md index 6a0086a434..d4250e255d 100644 --- a/guides/schema/definition.md +++ b/guides/schema/definition.md @@ -92,6 +92,8 @@ class MySchema < GraphQL::Schema end ``` +`resolve_type` is also used by `loads:` to confirm that loaded objects match the configured type. + __`object_from_id`__ is used by the `node(id: ID!): Node` field and `loads:` configuration. It receives a unique ID and must return the object for that ID, or `nil` if the object isn't found (or if it should be hidden from the current user). __`id_from_object`__ is used to implement `Node.id`. It should return a unique ID for the given object. This ID will later be sent to `object_from_id` to refetch the object. diff --git a/lib/graphql/schema.rb b/lib/graphql/schema.rb index 393282038d..72510f2da6 100644 --- a/lib/graphql/schema.rb +++ b/lib/graphql/schema.rb @@ -931,11 +931,7 @@ def resolve_type(type, obj, ctx) end def resolve_type(type, obj, ctx) - if type.kind.object? - type - else - raise GraphQL::RequiredImplementationMissingError, "#{self.name}.resolve_type(type, obj, ctx) must be implemented to use Union types or Interface types (tried to resolve: #{type.name})" - end + raise GraphQL::RequiredImplementationMissingError, "#{self.name}.resolve_type(type, obj, ctx) must be implemented to use Union types, Interface types, or `loads:` (tried to resolve: #{type.name})" end # rubocop:enable Lint/DuplicateMethods diff --git a/spec/graphql/dataloader_spec.rb b/spec/graphql/dataloader_spec.rb index 7811b2d40d..e54fa19121 100644 --- a/spec/graphql/dataloader_spec.rb +++ b/spec/graphql/dataloader_spec.rb @@ -964,6 +964,10 @@ class Schema < GraphQL::Schema def self.object_from_id(id, ctx) ctx.dataloader.with(Example::FooSource).request(id) end + + def self.resolve_type(type, obj, ctx) + type + end end end diff --git a/spec/graphql/schema/argument_spec.rb b/spec/graphql/schema/argument_spec.rb index 616dadd1f7..40ef54637b 100644 --- a/spec/graphql/schema/argument_spec.rb +++ b/spec/graphql/schema/argument_spec.rb @@ -92,6 +92,10 @@ def self.object_from_id(id, ctx) -> { Jazz::GloballyIdentifiableType.find(id) } end + def self.resolve_type(type, obj, ctx) + -> { type } # just for `loads:` + end + orphan_types [Jazz::InstrumentType, UnauthorizedInstrumentType] end end diff --git a/spec/graphql/schema/resolver_spec.rb b/spec/graphql/schema/resolver_spec.rb index 031c8b67ee..ec693ef427 100644 --- a/spec/graphql/schema/resolver_spec.rb +++ b/spec/graphql/schema/resolver_spec.rb @@ -509,6 +509,10 @@ def self.object_from_id(id, ctx) end end + def self.resolve_type(type, obj, ctx) + type # This will work for loaded objects well enough + end + rescue_from SpecialError do |err| raise GraphQL::ExecutionError, "A special error was raised from #{err.id.inspect}" end diff --git a/spec/graphql/schema/subscription_spec.rb b/spec/graphql/schema/subscription_spec.rb index 1863b9ac0d..498fa1fb6d 100644 --- a/spec/graphql/schema/subscription_spec.rb +++ b/spec/graphql/schema/subscription_spec.rb @@ -176,6 +176,10 @@ def self.object_from_id(id, ctx) USERS[id] end + def self.resolve_type(type, obj, ctx) + User + end + def self.unauthorized_field(err) path = err.context[:last_path] raise GraphQL::ExecutionError, "Can't subscribe to private user (#{path})"