JSONAPI_errors 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/GuardFile +82 -0
- data/LICENSE.txt +22 -0
- data/README.md +193 -0
- data/Rakefile +2 -0
- data/jsonapi_errors.gemspec +29 -0
- data/lib/jsonapi_errors/configuration.rb +109 -0
- data/lib/jsonapi_errors/hash_renderer.rb +26 -0
- data/lib/jsonapi_errors/rails/controller.rb +18 -0
- data/lib/jsonapi_errors/version.rb +3 -0
- data/lib/jsonapi_errors.rb +15 -0
- data/spec/lib/hash_renderer_spec.rb +78 -0
- data/spec/lib/rails/controller_spec.rb +35 -0
- data/spec/spec_helper.rb +10 -0
- metadata +161 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 801f0175a24b6f553fe658f4039526971e469a63
|
4
|
+
data.tar.gz: 4a5f7a01fec88054c01dafb3e08868d7befc843a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 43a6b5db8d0453aa5817299d13ceba5b4b92e77d9285b04c9db3296e7935321447fa28d6e05435c796992c531a00d76a69bb190a02ed1cf77b96540defd8fea3
|
7
|
+
data.tar.gz: 2b983887c97df735b3a9e83c5d85f210a72334e508e115cefba75e52b36a1dc3d075757451a2bb2bed3f3efe0e3fb09fdf6a974b2aa97e01ba02c5dcecebcfa7
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/GuardFile
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
## Uncomment and set this to only include directories you want to watch
|
5
|
+
# directories %w(app lib config test spec feature)
|
6
|
+
|
7
|
+
## Uncomment to clear the screen before every task
|
8
|
+
# clearing :on
|
9
|
+
|
10
|
+
## Guard internally checks for changes in the Guardfile and exits.
|
11
|
+
## If you want Guard to automatically start up again, run guard in a
|
12
|
+
## shell loop, e.g.:
|
13
|
+
##
|
14
|
+
## $ while bundle exec guard; do echo "Restarting Guard..."; done
|
15
|
+
##
|
16
|
+
## Note: if you are using the `directories` clause above and you are not
|
17
|
+
## watching the project directory ('.'), the you will want to move the Guardfile
|
18
|
+
## to a watched dir and symlink it back, e.g.
|
19
|
+
#
|
20
|
+
# $ mkdir config
|
21
|
+
# $ mv Guardfile config/
|
22
|
+
# $ ln -s config/Guardfile .
|
23
|
+
#
|
24
|
+
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"
|
25
|
+
|
26
|
+
# Note: The cmd option is now required due to the increasing number of ways
|
27
|
+
# rspec may be run, below are examples of the most common uses.
|
28
|
+
# * bundler: 'bundle exec rspec'
|
29
|
+
# * bundler binstubs: 'bin/rspec'
|
30
|
+
# * spring: 'bin/rspec' (This will use spring if running and you have
|
31
|
+
# installed the spring binstubs per the docs)
|
32
|
+
# * zeus: 'zeus rspec' (requires the server to be started separately)
|
33
|
+
# * 'just' rspec: 'rspec'
|
34
|
+
|
35
|
+
guard :rspec, cmd: "bundle exec rspec" do
|
36
|
+
require "guard/rspec/dsl"
|
37
|
+
dsl = Guard::RSpec::Dsl.new(self)
|
38
|
+
|
39
|
+
# Feel free to open issues for suggestions and improvements
|
40
|
+
|
41
|
+
# RSpec files
|
42
|
+
rspec = dsl.rspec
|
43
|
+
watch(rspec.spec_helper) { rspec.spec_dir }
|
44
|
+
watch(rspec.spec_support) { rspec.spec_dir }
|
45
|
+
watch(rspec.spec_files)
|
46
|
+
|
47
|
+
# Ruby files
|
48
|
+
ruby = dsl.ruby
|
49
|
+
dsl.watch_spec_files_for(ruby.lib_files)
|
50
|
+
|
51
|
+
# Rails files
|
52
|
+
rails = dsl.rails(view_extensions: %w(erb haml slim))
|
53
|
+
dsl.watch_spec_files_for(rails.app_files)
|
54
|
+
dsl.watch_spec_files_for(rails.views)
|
55
|
+
|
56
|
+
watch(rails.controllers) do |m|
|
57
|
+
[
|
58
|
+
rspec.spec.("routing/#{m[1]}_routing"),
|
59
|
+
rspec.spec.("controllers/#{m[1]}_controller"),
|
60
|
+
rspec.spec.("acceptance/#{m[1]}")
|
61
|
+
]
|
62
|
+
end
|
63
|
+
|
64
|
+
# Rails config changes
|
65
|
+
watch(rails.spec_helper) { rspec.spec_dir }
|
66
|
+
watch(rails.routes) { "#{rspec.spec_dir}/routing" }
|
67
|
+
watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" }
|
68
|
+
|
69
|
+
# Capybara features specs
|
70
|
+
watch(rails.view_dirs) { |m| rspec.spec.("features/#{m[1]}") }
|
71
|
+
|
72
|
+
# Turnip features and steps
|
73
|
+
watch(%r{^spec/acceptance/(.+)\.feature$})
|
74
|
+
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m|
|
75
|
+
Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance"
|
76
|
+
end
|
77
|
+
|
78
|
+
# Lib watch
|
79
|
+
watch(%r{^lib/(.+)/(.+)/(.+).rb$}) { |m| ["spec/lib/#{m[1]}/#{m[2]}/#{m[3]}_spec.rb"] }
|
80
|
+
watch(%r{^lib/(.+)/(.+).rb$}) { |m| ["spec/lib/#{m[1]}/#{m[2]}_spec.rb"] }
|
81
|
+
|
82
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Jacopo
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
# JSONAPIErrors
|
2
|
+
|
3
|
+
JSONAPIErrors is a Framework agnostic gem to handle errors compliant to [JSON API standard](http://jsonapi.org).
|
4
|
+
The gem at the moment is integrated with Rails ActionController but if there is some interest we can integrate the gem
|
5
|
+
with other popular Ruby frameworks such as Sinatra or Lotus.
|
6
|
+
|
7
|
+
The idea is to handle errors with ruby exceptions. When an exception is raised the application tries to match the exception classname
|
8
|
+
with the matched exception list and if the exception is found renders a json response confirm to [JSONAPI errors standard](http://jsonapi.org/format/#errors).
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
```ruby
|
15
|
+
gem 'JSONAPI_errors'
|
16
|
+
```
|
17
|
+
|
18
|
+
And then execute:
|
19
|
+
|
20
|
+
$ bundle
|
21
|
+
|
22
|
+
Or install it yourself as:
|
23
|
+
|
24
|
+
$ gem install JSONAPI_errors
|
25
|
+
|
26
|
+
Then
|
27
|
+
```ruby
|
28
|
+
include JSONAPIErrors::Rails::Controller
|
29
|
+
```
|
30
|
+
in your application_controller.rb or
|
31
|
+
in the controllers where you need to enable the gem.
|
32
|
+
|
33
|
+
## Usage
|
34
|
+
|
35
|
+
Add an element to the "JSONAPIErrors::Configuration.matches" hash for every exception error you need to handle.
|
36
|
+
Here is an example:
|
37
|
+
```ruby
|
38
|
+
JSONAPIErrors::Configuration.matches = {
|
39
|
+
# exception class name
|
40
|
+
"JSONAPIErrors::MatchedException" => {
|
41
|
+
# a unique identifier for this particular occurrence of the problem.
|
42
|
+
id: "1",
|
43
|
+
# a links object that follows [JSON API ERRORS standard](http://jsonapi.org/format/#errors)
|
44
|
+
links: "",
|
45
|
+
# the HTTP status code applicable to this problem, expressed as a string value.
|
46
|
+
# this value is equal to the response status code generated
|
47
|
+
status: "422",
|
48
|
+
# an application-specific error code, expressed as a string value.
|
49
|
+
code: "422",
|
50
|
+
# A short, human-readable summary of the problem
|
51
|
+
title: "Title",
|
52
|
+
# a human-readable explanation specific to this occurrence of the problem
|
53
|
+
detail: "Detail of the error",
|
54
|
+
# an object containing references to the source of the error
|
55
|
+
source: "/data",
|
56
|
+
# A meta object containing non-standard meta-information about the error.
|
57
|
+
meta: {"internal_error" => {}}
|
58
|
+
}
|
59
|
+
}
|
60
|
+
```
|
61
|
+
|
62
|
+
This package comes with a default configuration out of the box that handles all the rails default errors.
|
63
|
+
By default every exception that is not matched in the list is just raised up to the application, in order
|
64
|
+
to handle not matched errors you need to set the catch_unhandled_exceptions attribute to true. if
|
65
|
+
catch_unhandled_exceptions is set to true given the following exception:
|
66
|
+
```ruby
|
67
|
+
StandardError.new("msg")
|
68
|
+
```
|
69
|
+
you get this error response:
|
70
|
+
|
71
|
+
```
|
72
|
+
{
|
73
|
+
errors:[
|
74
|
+
{
|
75
|
+
title: "Unhandled exception",
|
76
|
+
detail: "The Exception: StandardError msg. is not handled in configuration.matches.",
|
77
|
+
status: "500"
|
78
|
+
}
|
79
|
+
]
|
80
|
+
}
|
81
|
+
```
|
82
|
+
|
83
|
+
Below here you can find a complete example
|
84
|
+
```ruby
|
85
|
+
JSONAPIErrors::Configuration.cofigure do |config|
|
86
|
+
config.matches = {
|
87
|
+
###
|
88
|
+
# ActiveRecord exceptions
|
89
|
+
###
|
90
|
+
"ActiveRecord::RecordInvalid" => {
|
91
|
+
status: "422",
|
92
|
+
code: "422"
|
93
|
+
},
|
94
|
+
"SubclassNotFound" => {
|
95
|
+
status: "422",
|
96
|
+
code: "422"
|
97
|
+
},
|
98
|
+
"AssociationTypeMismatch" => {
|
99
|
+
status: "422",
|
100
|
+
code: "422"
|
101
|
+
},
|
102
|
+
"SerializationTypeMismatch" => {
|
103
|
+
status: "422",
|
104
|
+
code: "422"
|
105
|
+
},
|
106
|
+
"AdapterNotSpecified" => {
|
107
|
+
status: "422",
|
108
|
+
code: "422"
|
109
|
+
},
|
110
|
+
"AdapterNotFound" => {
|
111
|
+
status: "422",
|
112
|
+
code: "422"
|
113
|
+
},
|
114
|
+
"ConnectionNotEstablished" => {
|
115
|
+
status: "422",
|
116
|
+
code: "422"
|
117
|
+
},
|
118
|
+
"RecordNotFound" => {
|
119
|
+
status: "422",
|
120
|
+
code: "422"
|
121
|
+
},
|
122
|
+
"RecordNotSaved" => {
|
123
|
+
status: "422",
|
124
|
+
code: "422"
|
125
|
+
},
|
126
|
+
"RecordNotDestroyed" => {
|
127
|
+
status: "422",
|
128
|
+
code: "422"
|
129
|
+
},
|
130
|
+
"StatementInvalid" => {
|
131
|
+
status: "422",
|
132
|
+
code: "422"
|
133
|
+
},
|
134
|
+
"PreparedStatementInvalid" => {
|
135
|
+
status: "422",
|
136
|
+
code: "422"
|
137
|
+
},
|
138
|
+
"StaleObjectError" => {
|
139
|
+
status: "422",
|
140
|
+
code: "422"
|
141
|
+
},
|
142
|
+
"ConfigurationError" => {
|
143
|
+
status: "422",
|
144
|
+
code: "422"
|
145
|
+
},
|
146
|
+
"ReadOnlyRecord" => {
|
147
|
+
status: "422",
|
148
|
+
code: "422"
|
149
|
+
},
|
150
|
+
"Rollback" => {
|
151
|
+
status: "422",
|
152
|
+
code: "422"
|
153
|
+
},
|
154
|
+
"DangerousAttributeError" => {
|
155
|
+
status: "422",
|
156
|
+
code: "422"
|
157
|
+
},
|
158
|
+
"AttributeAssignmentError" => {
|
159
|
+
status: "422",
|
160
|
+
code: "422"
|
161
|
+
},
|
162
|
+
"MultiparameterAssignmentErrors" => {
|
163
|
+
status: "422",
|
164
|
+
code: "422"
|
165
|
+
},
|
166
|
+
"UnknownPrimaryKey" => {
|
167
|
+
status: "422",
|
168
|
+
code: "422"
|
169
|
+
},
|
170
|
+
"ImmutableRelation" => {
|
171
|
+
status: "422",
|
172
|
+
code: "422"
|
173
|
+
},
|
174
|
+
"TransactionIsolationError" => {
|
175
|
+
status: "422",
|
176
|
+
code: "422"
|
177
|
+
}
|
178
|
+
}
|
179
|
+
|
180
|
+
# set true in order to catch not matched exceptions
|
181
|
+
config.catch_unhandled_exceptions = false
|
182
|
+
end
|
183
|
+
```
|
184
|
+
|
185
|
+
Put this file in a rails initializer in order to make it work as expected.
|
186
|
+
|
187
|
+
## Contributing
|
188
|
+
|
189
|
+
1. Fork it ( https://github.com/intrip/JSONAPI_errors/fork )
|
190
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
191
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
192
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
193
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'JSONAPI_errors/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "JSONAPI_errors"
|
8
|
+
spec.version = JSONAPIErrors::VERSION
|
9
|
+
spec.authors = ["Jacopo"]
|
10
|
+
spec.email = ["beschi.jacopo@gmail.com"]
|
11
|
+
spec.summary = %q{Framework agnostic gem to handle errors compliant to JSON API standard}
|
12
|
+
spec.description = %q{}
|
13
|
+
spec.homepage = "https://github.com/intrip/jsonapi_errors"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "activesupport"
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
25
|
+
spec.add_development_dependency "byebug"
|
26
|
+
spec.add_development_dependency "rspec"
|
27
|
+
spec.add_development_dependency "guard"
|
28
|
+
spec.add_development_dependency "guard-rspec"
|
29
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module JSONAPIErrors
|
2
|
+
class Configuration
|
3
|
+
cattr_accessor :matches do
|
4
|
+
{
|
5
|
+
###
|
6
|
+
# ActiveRecord exceptions
|
7
|
+
###
|
8
|
+
"ActiveRecord::RecordInvalid" => {
|
9
|
+
status: "422",
|
10
|
+
code: "422"
|
11
|
+
},
|
12
|
+
"SubclassNotFound" => {
|
13
|
+
status: "422",
|
14
|
+
code: "422"
|
15
|
+
},
|
16
|
+
"AssociationTypeMismatch" => {
|
17
|
+
status: "422",
|
18
|
+
code: "422"
|
19
|
+
},
|
20
|
+
"SerializationTypeMismatch" => {
|
21
|
+
status: "422",
|
22
|
+
code: "422"
|
23
|
+
},
|
24
|
+
"AdapterNotSpecified" => {
|
25
|
+
status: "422",
|
26
|
+
code: "422"
|
27
|
+
},
|
28
|
+
"AdapterNotFound" => {
|
29
|
+
status: "422",
|
30
|
+
code: "422"
|
31
|
+
},
|
32
|
+
"ConnectionNotEstablished" => {
|
33
|
+
status: "422",
|
34
|
+
code: "422"
|
35
|
+
},
|
36
|
+
"RecordNotFound" => {
|
37
|
+
status: "422",
|
38
|
+
code: "422"
|
39
|
+
},
|
40
|
+
"RecordNotSaved" => {
|
41
|
+
status: "422",
|
42
|
+
code: "422"
|
43
|
+
},
|
44
|
+
"RecordNotDestroyed" => {
|
45
|
+
status: "422",
|
46
|
+
code: "422"
|
47
|
+
},
|
48
|
+
"StatementInvalid" => {
|
49
|
+
status: "422",
|
50
|
+
code: "422"
|
51
|
+
},
|
52
|
+
"PreparedStatementInvalid" => {
|
53
|
+
status: "422",
|
54
|
+
code: "422"
|
55
|
+
},
|
56
|
+
"StaleObjectError" => {
|
57
|
+
status: "422",
|
58
|
+
code: "422"
|
59
|
+
},
|
60
|
+
"ConfigurationError" => {
|
61
|
+
status: "422",
|
62
|
+
code: "422"
|
63
|
+
},
|
64
|
+
"ReadOnlyRecord" => {
|
65
|
+
status: "422",
|
66
|
+
code: "422"
|
67
|
+
},
|
68
|
+
"Rollback" => {
|
69
|
+
status: "422",
|
70
|
+
code: "422"
|
71
|
+
},
|
72
|
+
"DangerousAttributeError" => {
|
73
|
+
status: "422",
|
74
|
+
code: "422"
|
75
|
+
},
|
76
|
+
"AttributeAssignmentError" => {
|
77
|
+
status: "422",
|
78
|
+
code: "422"
|
79
|
+
},
|
80
|
+
"MultiparameterAssignmentErrors" => {
|
81
|
+
status: "422",
|
82
|
+
code: "422"
|
83
|
+
},
|
84
|
+
"UnknownPrimaryKey" => {
|
85
|
+
status: "422",
|
86
|
+
code: "422"
|
87
|
+
},
|
88
|
+
"ImmutableRelation" => {
|
89
|
+
status: "422",
|
90
|
+
code: "422"
|
91
|
+
},
|
92
|
+
"TransactionIsolationError" => {
|
93
|
+
status: "422",
|
94
|
+
code: "422"
|
95
|
+
}
|
96
|
+
}
|
97
|
+
end
|
98
|
+
|
99
|
+
# if enabled return a json with unhandlex exception explanation
|
100
|
+
# otherwise just raises the exception
|
101
|
+
cattr_accessor :catch_unhandled_exceptions do
|
102
|
+
false
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.configure
|
106
|
+
yield self
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module JSONAPIErrors
|
2
|
+
class HashRenderer
|
3
|
+
attr_reader :exception
|
4
|
+
|
5
|
+
def initialize(exception)
|
6
|
+
@exception = exception
|
7
|
+
end
|
8
|
+
|
9
|
+
def render
|
10
|
+
return unhandled_exception_error unless data = JSONAPIErrors::Configuration.matches.fetch(@exception.class.to_s, false)
|
11
|
+
data.reverse_merge!({title: @exception.class.to_s, detail: @exception.message, status: "500"})
|
12
|
+
{errors: [data]}
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def unhandled_exception_error
|
18
|
+
unhandled_exception_error! unless JSONAPIErrors::Configuration::catch_unhandled_exceptions
|
19
|
+
{errors: [{title: "Unhandled exception", detail: "The Exception: #{@exception.class.name} #{@exception.message}. is not handled in configuration.matches.", status: "500"}]}
|
20
|
+
end
|
21
|
+
|
22
|
+
def unhandled_exception_error!
|
23
|
+
raise @exception
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module JSONAPIErrors
|
2
|
+
module Rails
|
3
|
+
module Controller
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
rescue_from StandardError, with: :render_error
|
8
|
+
end
|
9
|
+
|
10
|
+
#TODO set option to only and except for when using rescue_from
|
11
|
+
|
12
|
+
def render_error(exception)
|
13
|
+
response_h = HashRenderer.new(exception).render
|
14
|
+
render json: response_h, status: response_h[:status].to_i
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require "active_support"
|
2
|
+
require "active_support/concern"
|
3
|
+
require "active_support/core_ext/hash"
|
4
|
+
require "active_support/core_ext/class/attribute"
|
5
|
+
require "JSONAPI_errors/version"
|
6
|
+
require "JSONAPI_errors/configuration"
|
7
|
+
require "JSONAPI_errors/hash_renderer"
|
8
|
+
require "JSONAPI_errors/rails/controller"
|
9
|
+
|
10
|
+
module JSONAPIErrors
|
11
|
+
module Errors
|
12
|
+
# Gem specific errors
|
13
|
+
class UnhandledException < StandardError; end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module JSONAPIErrors
|
4
|
+
class MatchedException < StandardError;end
|
5
|
+
|
6
|
+
describe HashRenderer do
|
7
|
+
let(:matched_exception_data) {
|
8
|
+
{
|
9
|
+
id: "1",
|
10
|
+
links: "",
|
11
|
+
# you can override
|
12
|
+
status: "422",
|
13
|
+
code: "422",
|
14
|
+
# you can override
|
15
|
+
title: "Title",
|
16
|
+
# you can override
|
17
|
+
detail: "Detail of the error",
|
18
|
+
source: "/data",
|
19
|
+
meta: {"internal_error" => {}}
|
20
|
+
}
|
21
|
+
}
|
22
|
+
before do
|
23
|
+
JSONAPIErrors::Configuration.matches = {
|
24
|
+
"JSONAPIErrors::MatchedException" => matched_exception_data
|
25
|
+
}
|
26
|
+
end
|
27
|
+
subject {HashRenderer.new(exception)}
|
28
|
+
let(:exception) { StandardError.new("msg") }
|
29
|
+
it 'has attr_reader for exception' do
|
30
|
+
expect(subject.exception).to eq exception
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#render" do
|
34
|
+
context 'exception not present in exception_matches' do
|
35
|
+
let(:exception) { StandardError.new("msg") }
|
36
|
+
context 'catch_unhandled_exceptions == true' do
|
37
|
+
before {JSONAPIErrors::Configuration.catch_unhandled_exceptions = true}
|
38
|
+
it 'renders json containing the Unhandled exception data' do
|
39
|
+
expect(subject.render).to eq({errors:
|
40
|
+
[{title: "Unhandled exception",
|
41
|
+
detail: "The Exception: StandardError msg. is not handled in configuration.matches.",
|
42
|
+
status: "500"}]
|
43
|
+
})
|
44
|
+
end
|
45
|
+
end
|
46
|
+
context 'catch_unhandled_exceptions == false' do
|
47
|
+
before {JSONAPIErrors::Configuration.catch_unhandled_exceptions = false}
|
48
|
+
it 'raises the exception up' do
|
49
|
+
expect{subject.render}.to raise_error StandardError, "msg"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
context 'exception present in matches' do
|
54
|
+
let(:exception) {MatchedException.new("exception message")}
|
55
|
+
context 'exception inherits from JSONAPIErrorsException' do
|
56
|
+
context 'the exception values are overridden' do
|
57
|
+
xit 'renders error hash with the overridden values'
|
58
|
+
end
|
59
|
+
context 'the exception values are not given' do
|
60
|
+
xit 'renders error hash using the default exception values present in the class'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'status,description and title are overridden' do
|
65
|
+
it 'renders error hash with the overridden values' do
|
66
|
+
expect(subject.render).to eq({errors: [matched_exception_data]})
|
67
|
+
end
|
68
|
+
end
|
69
|
+
context 'status,description and title are not overridden' do
|
70
|
+
let(:matched_exception_data) { Hash.new }
|
71
|
+
it 'renders error hash with status 500 title Exception class and detail exception message' do
|
72
|
+
expect(subject.render).to eq({errors: [{title: "JSONAPIErrors::MatchedException", detail: "exception message", status: "500"}]})
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module JSONAPIErrors
|
4
|
+
module Rails
|
5
|
+
describe Controller do
|
6
|
+
describe '#rescue_from' do
|
7
|
+
class Stub; end
|
8
|
+
before {expect(Stub).to receive(:rescue_from).with(StandardError, with: :render_error)}
|
9
|
+
it 'rescue StandardError with #render_error' do
|
10
|
+
Stub.class_eval do
|
11
|
+
include Controller
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class RailsControllerStub
|
17
|
+
def self.rescue_from(*klasses, &block);end
|
18
|
+
|
19
|
+
include JSONAPIErrors::Rails::Controller
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#render_error' do
|
23
|
+
subject{RailsControllerStub.new}
|
24
|
+
let(:exception) {StandardError.new}
|
25
|
+
before do
|
26
|
+
expect(HashRenderer).to receive(:new).with(exception).and_return(double(render: {status: "422", title: "Title", detail: "Detail of the error"}))
|
27
|
+
end
|
28
|
+
it 'renders json from HashRenderer#render data and status' do
|
29
|
+
expect(subject).to receive(:render).with(json: {status: "422", title: "Title", detail: "Detail of the error"}, status: 422)
|
30
|
+
subject.render_error(exception)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'JSONAPI_errors'
|
3
|
+
require 'byebug'
|
4
|
+
Dir[File.dirname(__FILE__) + '/support/**/*.rb'].each { |f| require f }
|
5
|
+
|
6
|
+
RSpec.configure do |config|
|
7
|
+
config.filter_run :focus
|
8
|
+
config.run_all_when_everything_filtered = true
|
9
|
+
config.color = true
|
10
|
+
end
|
metadata
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: JSONAPI_errors
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jacopo
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-02-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.7'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.7'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: byebug
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: guard
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: guard-rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: ''
|
112
|
+
email:
|
113
|
+
- beschi.jacopo@gmail.com
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- ".gitignore"
|
119
|
+
- Gemfile
|
120
|
+
- GuardFile
|
121
|
+
- LICENSE.txt
|
122
|
+
- README.md
|
123
|
+
- Rakefile
|
124
|
+
- jsonapi_errors.gemspec
|
125
|
+
- lib/jsonapi_errors.rb
|
126
|
+
- lib/jsonapi_errors/configuration.rb
|
127
|
+
- lib/jsonapi_errors/hash_renderer.rb
|
128
|
+
- lib/jsonapi_errors/rails/controller.rb
|
129
|
+
- lib/jsonapi_errors/version.rb
|
130
|
+
- spec/lib/hash_renderer_spec.rb
|
131
|
+
- spec/lib/rails/controller_spec.rb
|
132
|
+
- spec/spec_helper.rb
|
133
|
+
homepage: https://github.com/intrip/jsonapi_errors
|
134
|
+
licenses:
|
135
|
+
- MIT
|
136
|
+
metadata: {}
|
137
|
+
post_install_message:
|
138
|
+
rdoc_options: []
|
139
|
+
require_paths:
|
140
|
+
- lib
|
141
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - ">="
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
requirements: []
|
152
|
+
rubyforge_project:
|
153
|
+
rubygems_version: 2.2.2
|
154
|
+
signing_key:
|
155
|
+
specification_version: 4
|
156
|
+
summary: Framework agnostic gem to handle errors compliant to JSON API standard
|
157
|
+
test_files:
|
158
|
+
- spec/lib/hash_renderer_spec.rb
|
159
|
+
- spec/lib/rails/controller_spec.rb
|
160
|
+
- spec/spec_helper.rb
|
161
|
+
has_rdoc:
|