add custom error formatter (#76)

This commit is contained in:
Christian Trosclair 2017-10-20 10:26:32 -04:00 committed by Daniel Doubrovkine (dB.) @dblockdotorg
parent fab476772e
commit b2654190c1
6 changed files with 185 additions and 10 deletions

View file

@ -1,20 +1,48 @@
# This configuration was generated by `rubocop --auto-gen-config`
# on 2015-01-13 18:47:14 -0500 using RuboCop version 0.28.0.
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2017-10-09 10:22:52 -0500 using RuboCop version 0.41.2.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.
# Offense count: 25
# Configuration parameters: AllowURI, URISchemes.
# Offense count: 1
Metrics/AbcSize:
Max: 20
Max: 18
# Offense count: 7
# Offense count: 1
Metrics/CyclomaticComplexity:
Max: 9
# Offense count: 1
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes.
# URISchemes: http, https
Metrics/LineLength:
Max: 87
# Offense count: 1
# Configuration parameters: CountComments.
Metrics/MethodLength:
Max: 18
# Offense count: 1
Metrics/PerceivedComplexity:
Max: 11
# Offense count: 5
Style/Documentation:
Enabled: false
Exclude:
- 'spec/**/*'
- 'test/**/*'
- 'lib/grape-active_model_serializers/endpoint_extension.rb'
- 'lib/grape-active_model_serializers/error_formatter.rb'
- 'lib/grape-active_model_serializers/formatter.rb'
- 'lib/grape-active_model_serializers/options_builder.rb'
- 'lib/grape-active_model_serializers/serializer_resolver.rb'
# Offense count: 2
# Configuration parameters: Exclude.
# Configuration parameters: ExpectMatchingDefinition, Regex, IgnoreExecutableScripts.
Style/FileName:
Enabled: false
Exclude:
- 'lib/grape-active_model_serializers.rb'
- 'spec/grape-active_model_serializers_spec.rb'

View file

@ -2,6 +2,7 @@
### 1.5.2 (Next)
* [#76](https://github.com/ruby-grape/grape-active_model_serializers/pull/76): Add custom error formatter - [@xn](https://github.com/xn).
* Your contribution here.
### 1.5.1 (April 25, 2017)

View file

@ -2,7 +2,7 @@ source 'https://rubygems.org'
gemspec
case version = ENV['GRAPE_VERSION'] || '~> 0.10.0'
case version = ENV['GRAPE_VERSION'] || '~> 1.0.0'
when 'HEAD'
gem 'grape', github: 'intridea/grape'
else

View file

@ -1,6 +1,7 @@
require 'active_model_serializers'
require 'grape'
require 'grape-active_model_serializers/endpoint_extension'
require 'grape-active_model_serializers/error_formatter'
require 'grape-active_model_serializers/formatter'
require 'grape-active_model_serializers/serializer_resolver'
require 'grape-active_model_serializers/options_builder'

View file

@ -0,0 +1,53 @@
module Grape
module ErrorFormatter
module ActiveModelSerializers
extend Base
class << self
def call(message, backtrace, options = {}, env = nil, original_exception = nil)
message = present(message, env) if respond_to?(:present)
message = wrap_message(message)
rescue_options = options[:rescue_options] || {}
if rescue_options[:backtrace] && backtrace && !backtrace.empty?
message = message.merge(backtrace: backtrace)
end
if rescue_options[:original_exception] && original_exception
message = message
.merge(original_exception: original_exception.inspect)
end
if ::Grape.const_defined? :Json
::Grape::Json.dump(message)
else
::MultiJson.dump(message)
end
end
private
def wrap_message(message)
if active_model?(message)
::ActiveModelSerializers::SerializableResource.new(
message,
serializer: ActiveModel::Serializer::ErrorSerializer
).as_json
elsif ok_to_pass_through?(message)
message
else
{ error: message }
end
end
def active_model?(message)
message.respond_to?(:errors) &&
message.errors.is_a?(ActiveModel::Errors)
end
def ok_to_pass_through?(message)
message.is_a?(Exceptions::ValidationErrors) ||
message.is_a?(Hash)
end
end
end
end
end

View file

@ -0,0 +1,92 @@
require 'spec_helper'
require 'grape-active_model_serializers/error_formatter'
describe Grape::ErrorFormatter::ActiveModelSerializers do
subject { Grape::ErrorFormatter::ActiveModelSerializers }
let(:backtrace) { ['Line:1'] }
let(:options) { Hash.new }
let(:env) { { 'api.endpoint' => app.endpoints.first } }
let(:original_exception) { StandardError.new('oh noes!') }
let(:app) {
Class.new(Grape::API) do |app|
app.format :json
app.formatter :jsonapi, Grape::Formatter::ActiveModelSerializers
app.error_formatter :jsonapi, Grape::ErrorFormatter::ActiveModelSerializers
app.namespace('space') do |ns|
ns.get('/', root: false) do
error!(message)
end
end
end
}
let(:foo) {
Class.new {
include ActiveModel::Model
attr_accessor :name
def initialize(attributes = {})
super
errors.add(:name, 'We don\'t like bears')
end
}
}
before do
ActiveModel::Serializer.config.adapter = :json_api
end
after do
ActiveModel::Serializer.config.adapter = :json
end
describe '#call' do
context 'message is an activemodel' do
let(:message) {
foo.new(name: 'bar')
}
it 'formats the error' do
result = subject
.call(message, backtrace, options, env, original_exception)
json_hash = JSON.parse(result)
expected_result = {
'errors' => [
{
'source' => {
'pointer' => '/data/attributes/name'
},
'detail' => 'We don\'t like bears'
}
]
}
expect(json_hash == expected_result).to eq(true)
end
end
context 'message is hash like' do
let(:message) { { 'errors' => ['error'] } }
it 'passes the message through' do
result = subject
.call(message, backtrace, options, env, original_exception)
json_hash = JSON.parse(result)
expect(json_hash == message).to eq(true)
end
end
context 'message is text' do
let(:message) { 'error' }
it 'wraps the error' do
result = subject
.call(message, backtrace, options, env, original_exception)
json_hash = JSON.parse(result)
expect(json_hash == { 'error' => message }).to eq(true)
end
end
end
end