Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Error Instrumentation
# frozen_string_literal: true
class ErrorInstrumentation
def instrument(type, field)
old_resolver = field.resolve_proc
new_resolver = -> (obj, args, ctx) do
begin # rubocop:disable Style/RedundantBegin
result = old_resolver.call(obj, args, ctx)
if result.is_a?(StandardError)
set_error_context(result, type, obj, field, args, ctx)
elsif result.is_a?(Promise)
result.rescue do |error|
set_error_context(error, type, obj, field, args, ctx)
raise error
end
result = result.then do |next_result|
set_error_context(next_result, type, obj, field, args, ctx) if next_result.is_a?(StandardError)
next_result
end
end
result
rescue => ex
set_error_context(ex, type, obj, field, args, ctx)
raise
end
end
field.redefine { resolve(new_resolver) }
end
def set_error_context(exception, graphql_type, object, field_definition, args, context)
object_path = { 'type' => object.class.name }
begin
object_path['id'] = object.id if object.respond_to?(:id)
object_path['gid'] = object.gid if object.respond_to?(:gid)
rescue # rubocop:disable Lint/HandleExceptions
# noop
end
error_context = exception.instance_variable_get(:@_graphql_error_context)
if error_context
error_context['object_path'] = Array.wrap(error_context['object_path'])
error_context['object_path'].unshift(object_path)
else
error_context = {
'graphql_type' => graphql_type.name,
'field' => field_definition.name,
'args' => args.to_h,
'path' => context.path,
'object' => object_path,
}
exception.instance_variable_set(:@_graphql_error_context, error_context)
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.