Class: GraphQL::Execution::Errors
- Inherits:
-
Object
- Object
- GraphQL::Execution::Errors
- Defined in:
- lib/graphql/execution/errors.rb
Overview
A plugin that wraps query execution with error handling. Supports class-based schemas and the new Interpreter runtime only.
Constant Summary collapse
- NEW_HANDLER_HASH =
->(h, k) { h[k] = { class: k, handler: nil, subclass_handlers: Hash.new(&NEW_HANDLER_HASH), } }
Class Method Summary collapse
Instance Method Summary collapse
- #each_rescue ⇒ Object private
-
#find_handler_for(error_class) ⇒ Proc?
The handler for
error_class
, if one was registered on this schema or inherited. -
#initialize(schema) ⇒ Errors
constructor
A new instance of Errors.
-
#rescue_from(error_class, error_handler) ⇒ void
Register this handler, updating the internal handler index to maintain least-to-most specific.
-
#with_error_handling(ctx) ⇒ Object
Call the given block with the schema's configured error handlers.
Constructor Details
#initialize(schema) ⇒ Errors
Returns a new instance of Errors.
33 34 35 36 37 38 39 40 |
# File 'lib/graphql/execution/errors.rb', line 33 def initialize(schema) @schema = schema @handlers = { class: nil, handler: nil, subclass_handlers: Hash.new(&NEW_HANDLER_HASH), } end |
Class Method Details
.use(schema) ⇒ Object
20 21 22 23 |
# File 'lib/graphql/execution/errors.rb', line 20 def self.use(schema) definition_line = caller(2, 1).first GraphQL::Deprecation.warn("GraphQL::Execution::Errors is now installed by default, remove `use GraphQL::Execution::Errors` from #{definition_line}") end |
Instance Method Details
#each_rescue ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
43 44 45 46 47 48 49 |
# File 'lib/graphql/execution/errors.rb', line 43 def each_rescue handlers = @handlers.values while (handler = handlers.shift) do yield(handler[:class], handler[:handler]) handlers.concat(handler[:subclass_handlers].values) end end |
#find_handler_for(error_class) ⇒ Proc?
Returns The handler for error_class
, if one was registered on this schema or inherited.
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/graphql/execution/errors.rb', line 126 def find_handler_for(error_class) handlers = @handlers[:subclass_handlers] handler = nil while (handlers) do _err_class, next_handler = handlers.find { |err_class, handler| error_class <= err_class } if next_handler handlers = next_handler[:subclass_handlers] handler = next_handler else # Don't reassign `handler` -- # let the previous assignment carry over outside this block. break end end # check for a handler from a parent class: if @schema.superclass.respond_to?(:error_handler) && (parent_errors = @schema.superclass.error_handler) parent_handler = parent_errors.find_handler_for(error_class) end # If the inherited handler is more specific than the one defined here, # use it. # If it's a tie (or there is no parent handler), use the one defined here. # If there's an inherited one, but not one defined here, use the inherited one. # Otherwise, there's no handler for this error, return `nil`. if parent_handler && handler && parent_handler[:class] < handler[:class] parent_handler elsif handler handler elsif parent_handler parent_handler else nil end end |
#rescue_from(error_class, error_handler) ⇒ void
This method returns an undefined value.
Register this handler, updating the internal handler index to maintain least-to-most specific.
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 93 94 95 96 97 98 |
# File 'lib/graphql/execution/errors.rb', line 57 def rescue_from(error_class, error_handler) subclasses_handlers = {} this_level_subclasses = [] # During this traversal, do two things: # - Identify any already-registered subclasses of this error class # and gather them up to be inserted _under_ this class # - Find the point in the index where this handler should be inserted # (That is, _under_ any superclasses, or at top-level, if there are no superclasses registered) handlers = @handlers[:subclass_handlers] while (handlers) do this_level_subclasses.clear # First, identify already-loaded handlers that belong # _under_ this one. (That is, they're handlers # for subclasses of `error_class`.) handlers.each do |err_class, handler| if err_class < error_class subclasses_handlers[err_class] = handler this_level_subclasses << err_class end end # Any handlers that we'll be moving, delete them from this point in the index this_level_subclasses.each do |err_class| handlers.delete(err_class) end # See if any keys in this hash are superclasses of this new class: next_index_point = handlers.find { |err_class, handler| error_class < err_class } if next_index_point handlers = next_index_point[1][:subclass_handlers] else # this new handler doesn't belong to any sub-handlers, # so insert it in the current set of `handlers` break end end # Having found the point at which to insert this handler, # register it and merge any subclass handlers back in at this point. this_class_handlers = handlers[error_class] this_class_handlers[:handler] = error_handler this_class_handlers[:subclass_handlers].merge!(subclasses_handlers) nil end |
#with_error_handling(ctx) ⇒ Object
Call the given block with the schema's configured error handlers.
If the block returns a lazy value, it's not wrapped with error handling. That area will have to be wrapped itself.
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/graphql/execution/errors.rb', line 106 def with_error_handling(ctx) yield rescue StandardError => err handler = find_handler_for(err.class) if handler runtime_info = ctx.namespace(:interpreter) || {} obj = runtime_info[:current_object] args = runtime_info[:current_arguments] args = args && args.keyword_arguments field = runtime_info[:current_field] if obj.is_a?(GraphQL::Schema::Object) obj = obj.object end handler[:handler].call(err, obj, args, ctx, field) else raise err end end |