Skip to content

Instantly share code, notes, and snippets.

@monorkin
Created November 19, 2018 08:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save monorkin/63ca08012292838c579c7c23787cea61 to your computer and use it in GitHub Desktop.
Save monorkin/63ca08012292838c579c7c23787cea61 to your computer and use it in GitHub Desktop.
A simple yet effective GraphQL error builder for Ruby
# frozen_string_literal: true
# BasicService implements `self.call(*args)` so that you can
# use `ErrorObjectsBuilder.call(errors)` instead of
# `ErrorObjectsBuilder.new(errors).call`
class ErrorObjectsBuilder < BasicService
Error = Struct.new(:key, :index, :messages, :suberrors)
def initialize(errors, camelize_keys = true)
@errors = errors
@camelize_keys = camelize_keys
end
def call
return [] unless errors
errors.map { |key, messages| build_error(key, messages) }
end
protected
attr_reader :errors
attr_reader :camelize_keys
private
def build_error(key, messages)
index = nil
suberrors = nil
if messages.is_a?(Hash)
suberrors =
messages.map { |subkey, submessages| build_error(subkey, submessages) }
messages = nil
end
if key.class == Integer
index = key.dup
key = nil
else
key = camelize_key(key)
end
Error.new(key, index, messages && Array(messages), suberrors)
end
def camelize_key(key)
return key unless camelize_keys
return key unless key.respond_to?(:to_s)
key.to_s.camelize(:lower)
end
end
# The output of this is an array of hashes that has the following structure
# ```JSON
# {
# "key": "password",
# "messages": [
#. "must be longer than 8 characters",
# "must contain a symbol"
# ],
# "index": null,
# "suberrors": null
# }
# ```
#
# If there is a nested error. Say, that an user is creating
# a gallery of images and the 5th image is actually a video
# (has an invalid file type).
# ```JSON
# {
# "key": "images",
# "messages": null,
# "index": null,
# "suberrors": [
# {
# "key": "password",
# "messages": [
#. "must be an image (jpeg/gif/png/bmp)"
# ],
# "index": 4,
# "suberrors": null
# }
#. ]
# }
# ```
# Conversly, the same pattern can be applied for nested
# objects (then the index field is `null`).
#
# In later versions the first element of the `messages` array
# has been exposed under the key `message` though this is not
# necessary. It's here to add compatibility with standard GQL
# errors and therefor with existing libraries. E.g.
# ```JSON
# {
# "key": "password",
#. "message": "Password must be longer than 8 characters",
# "messages": [
#. "must be longer than 8 characters",
# "must contain a symbol"
# ],
# "index": null,
# "suberrors": null
# }
# ```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment