jsonapi-consumer 0.1.1 → 1.0.0
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 +5 -5
- data/.circleci/config.yml +27 -0
- data/.gitignore +1 -0
- data/Gemfile +6 -4
- data/README.md +9 -38
- data/Rakefile +17 -6
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/jsonapi-consumer.gemspec +10 -11
- data/lib/jsonapi/consumer/associations/base_association.rb +26 -0
- data/lib/jsonapi/consumer/associations/belongs_to.rb +30 -0
- data/lib/jsonapi/consumer/associations/has_many.rb +26 -0
- data/lib/jsonapi/consumer/associations/has_one.rb +19 -0
- data/lib/jsonapi/consumer/connection.rb +36 -0
- data/lib/jsonapi/consumer/error_collector.rb +91 -0
- data/lib/jsonapi/consumer/errors.rb +34 -76
- data/lib/jsonapi/consumer/formatter.rb +145 -0
- data/lib/jsonapi/consumer/helpers/callbacks.rb +27 -0
- data/lib/jsonapi/consumer/helpers/dirty.rb +71 -0
- data/lib/jsonapi/consumer/helpers/dynamic_attributes.rb +83 -0
- data/lib/jsonapi/consumer/helpers/uri.rb +9 -0
- data/lib/jsonapi/consumer/implementation.rb +12 -0
- data/lib/jsonapi/consumer/included_data.rb +49 -0
- data/lib/jsonapi/consumer/linking/links.rb +22 -0
- data/lib/jsonapi/consumer/linking/top_level_links.rb +39 -0
- data/lib/jsonapi/consumer/meta_data.rb +19 -0
- data/lib/jsonapi/consumer/middleware/json_request.rb +26 -0
- data/lib/jsonapi/consumer/middleware/parse_json.rb +22 -23
- data/lib/jsonapi/consumer/middleware/status.rb +41 -0
- data/lib/jsonapi/consumer/paginating/paginator.rb +89 -0
- data/lib/jsonapi/consumer/parsers/parser.rb +113 -0
- data/lib/jsonapi/consumer/query/builder.rb +212 -0
- data/lib/jsonapi/consumer/query/requestor.rb +67 -0
- data/lib/jsonapi/consumer/relationships/relations.rb +56 -0
- data/lib/jsonapi/consumer/relationships/top_level_relations.rb +30 -0
- data/lib/jsonapi/consumer/resource.rb +514 -54
- data/lib/jsonapi/consumer/result_set.rb +25 -0
- data/lib/jsonapi/consumer/schema.rb +153 -0
- data/lib/jsonapi/consumer/utils.rb +28 -0
- data/lib/jsonapi/consumer/version.rb +1 -1
- data/lib/jsonapi/consumer.rb +59 -34
- metadata +51 -111
- data/.rspec +0 -2
- data/CHANGELOG.md +0 -36
- data/lib/jsonapi/consumer/middleware/raise_error.rb +0 -21
- data/lib/jsonapi/consumer/middleware/request_headers.rb +0 -20
- data/lib/jsonapi/consumer/middleware/request_timeout.rb +0 -9
- data/lib/jsonapi/consumer/middleware.rb +0 -5
- data/lib/jsonapi/consumer/parser.rb +0 -75
- data/lib/jsonapi/consumer/query/base.rb +0 -34
- data/lib/jsonapi/consumer/query/create.rb +0 -9
- data/lib/jsonapi/consumer/query/delete.rb +0 -10
- data/lib/jsonapi/consumer/query/find.rb +0 -16
- data/lib/jsonapi/consumer/query/new.rb +0 -15
- data/lib/jsonapi/consumer/query/update.rb +0 -11
- data/lib/jsonapi/consumer/query.rb +0 -5
- data/lib/jsonapi/consumer/resource/association_concern.rb +0 -203
- data/lib/jsonapi/consumer/resource/attributes_concern.rb +0 -70
- data/lib/jsonapi/consumer/resource/connection_concern.rb +0 -99
- data/lib/jsonapi/consumer/resource/finders_concern.rb +0 -28
- data/lib/jsonapi/consumer/resource/object_build_concern.rb +0 -28
- data/lib/jsonapi/consumer/resource/serializer_concern.rb +0 -63
- data/spec/fixtures/.gitkeep +0 -0
- data/spec/fixtures/resources.rb +0 -45
- data/spec/fixtures/responses.rb +0 -64
- data/spec/jsonapi/consumer/associations_spec.rb +0 -166
- data/spec/jsonapi/consumer/attributes_spec.rb +0 -27
- data/spec/jsonapi/consumer/connection_spec.rb +0 -147
- data/spec/jsonapi/consumer/error_handling_spec.rb +0 -37
- data/spec/jsonapi/consumer/object_build_spec.rb +0 -20
- data/spec/jsonapi/consumer/parser_spec.rb +0 -39
- data/spec/jsonapi/consumer/resource_spec.rb +0 -62
- data/spec/jsonapi/consumer/serializer_spec.rb +0 -41
- data/spec/spec_helper.rb +0 -97
- data/spec/support/.gitkeep +0 -0
- data/spec/support/load_fixtures.rb +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1dada35491a8ef6e7c3128cb4636bb126a903f5d2081998719033486b6252246
|
4
|
+
data.tar.gz: 16ea1a557a08f41f8581edae35e5fd83820ea0b3915a719121ddf0e14b45a5a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 39d0ca8e2933a7e73f005bcd95d45fb43ffa0d193f41017cc768cb5721c15a3ce36eed77c734a9e0c9fe800f4a31038d65aa97dfc566daf4ae46531eb73e02f8
|
7
|
+
data.tar.gz: 2f4985cc2d24da2721699a752938b7c2a78238e6cf786c16c708a71e8af9091bb5f50b2f043480c9558c8ad68cb7289aae9440eafc53d5d6ac61605e67e92aa5
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# Ruby CircleCI 2.0 configuration file
|
2
|
+
#
|
3
|
+
# Check https://circleci.com/docs/2.0/language-ruby/ for more details
|
4
|
+
#
|
5
|
+
version: 2
|
6
|
+
jobs:
|
7
|
+
build:
|
8
|
+
docker:
|
9
|
+
# specify the version you desire here
|
10
|
+
- image: circleci/ruby:2.5
|
11
|
+
working_directory: ~/jsonapi_consumer
|
12
|
+
|
13
|
+
steps:
|
14
|
+
- checkout
|
15
|
+
|
16
|
+
- run:
|
17
|
+
name: install dependencies
|
18
|
+
command: |
|
19
|
+
bundle install --jobs=4 --retry=3 --path vendor/bundle
|
20
|
+
|
21
|
+
- run:
|
22
|
+
command: env CI=true bundle exec rake test
|
23
|
+
when: always
|
24
|
+
|
25
|
+
# collect reports
|
26
|
+
- store_test_results:
|
27
|
+
path: /tmp/reports
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
@@ -1,7 +1,9 @@
|
|
1
|
-
source
|
1
|
+
source "https://rubygems.org"
|
2
|
+
|
3
|
+
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
2
4
|
|
3
|
-
# Specify your gem's dependencies in jsonapi-consumer.gemspec
|
4
5
|
gemspec
|
5
6
|
|
6
|
-
gem '
|
7
|
-
gem '
|
7
|
+
gem 'rake'
|
8
|
+
gem 'minitest-ci'
|
9
|
+
gem 'pry'
|
data/README.md
CHANGED
@@ -2,33 +2,30 @@
|
|
2
2
|
|
3
3
|
An ActiveModel-compliant consumer framework for communicating with JSONAPI-based APIs.
|
4
4
|
|
5
|
-
[](https://circleci.com/gh/jsmestad/jsonapi-consumer)
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
9
9
|
Add this line to your application's Gemfile:
|
10
10
|
|
11
11
|
```ruby
|
12
|
-
gem 'jsonapi-consumer'
|
12
|
+
gem 'jsonapi-consumer', '~> 1.0'
|
13
13
|
```
|
14
14
|
|
15
15
|
And then execute:
|
16
16
|
|
17
17
|
$ bundle
|
18
18
|
|
19
|
-
Or install it yourself as:
|
20
|
-
|
21
|
-
$ gem install jsonapi-consumer
|
22
|
-
|
23
19
|
## Usage
|
24
20
|
|
25
21
|
It's suggested to create a base resource for the whole API that you can re-use.
|
26
22
|
|
27
23
|
```ruby
|
28
|
-
class Base
|
29
|
-
|
30
|
-
|
31
|
-
self.
|
24
|
+
class Base < JSONAPI::Consumer::Resource
|
25
|
+
# self.connection_options = {} # Faraday connection options
|
26
|
+
# self.json_key_format = :dasherized_key # (default: underscored_key)
|
27
|
+
# self.route_format = :dasherized_route # (default: underscored_route)
|
28
|
+
self.site = 'http://localhost:3000/api/'
|
32
29
|
end
|
33
30
|
```
|
34
31
|
|
@@ -36,7 +33,6 @@ Then inherit from that Base class for each resource defined in your API.
|
|
36
33
|
|
37
34
|
```ruby
|
38
35
|
module Blog
|
39
|
-
|
40
36
|
class Author < Base
|
41
37
|
has_many :posts, class_name: 'Blog::Post'
|
42
38
|
end
|
@@ -53,36 +49,9 @@ module Blog
|
|
53
49
|
class Comment < Base
|
54
50
|
|
55
51
|
end
|
56
|
-
|
57
52
|
end
|
58
53
|
```
|
59
54
|
|
60
|
-
#### Additional Features
|
61
|
-
|
62
|
-
##### Dynamic Objects
|
63
|
-
|
64
|
-
By default calling `.new` or `.build` on a resource will give you an empty
|
65
|
-
object with no attributes defined. This is less than ideal when building forms
|
66
|
-
with something like Rails' FormBuilder.
|
67
|
-
|
68
|
-
We suggest setting up your model to do a `GET /{resource_name}/new` if your
|
69
|
-
server supports it and using `.build` instead of `.new`. This will populate the
|
70
|
-
object with defaults set by the server response.
|
71
|
-
|
72
|
-
```ruby
|
73
|
-
class User
|
74
|
-
include JSONAPI::Consumer::Resource
|
75
|
-
|
76
|
-
self.request_new_object_on_build = true
|
77
|
-
|
78
|
-
# .build will now call GET /users/new
|
79
|
-
end
|
80
|
-
```
|
81
|
-
|
82
|
-
#### Testing
|
83
|
-
|
84
|
-
We suggest [Webmock](https://github.com/bblimke/webmock) at this stage in
|
85
|
-
development. We plan to add test helpers before the first major release.
|
86
55
|
|
87
56
|
## Contributing
|
88
57
|
|
@@ -95,3 +64,5 @@ development. We plan to add test helpers before the first major release.
|
|
95
64
|
## Copyright & License
|
96
65
|
|
97
66
|
JSONAPI::Consumer is distributed under the Apache 2.0 License. See LICENSE.txt file for more information.
|
67
|
+
|
68
|
+
Version v1 is a rewrite is based on the excellent work by [json_api_client](https://github.com/chingor13/json_api_client) [v1.5.3](https://github.com/chingor13/json_api_client/tree/v1.5.3).
|
data/Rakefile
CHANGED
@@ -1,12 +1,23 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
2
|
|
3
|
-
|
4
|
-
require 'rspec/core/rake_task'
|
3
|
+
require 'rdoc/task'
|
5
4
|
|
6
|
-
|
5
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
6
|
+
rdoc.rdoc_dir = 'rdoc'
|
7
|
+
rdoc.title = 'JsonApiClient'
|
8
|
+
rdoc.options << '--line-numbers'
|
9
|
+
rdoc.rdoc_files.include('README.rdoc')
|
10
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
require 'rake/testtask'
|
7
15
|
|
8
|
-
|
9
|
-
|
10
|
-
|
16
|
+
Rake::TestTask.new(:test) do |t|
|
17
|
+
t.libs << 'lib'
|
18
|
+
t.libs << 'test'
|
19
|
+
t.pattern = 'test/**/*_test.rb'
|
20
|
+
t.verbose = false
|
11
21
|
end
|
12
22
|
|
23
|
+
task default: :test
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "mikasa_client"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
require "pry"
|
11
|
+
Pry.start(__FILE__)
|
12
|
+
|
13
|
+
# require "irb"
|
14
|
+
# IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/jsonapi-consumer.gemspec
CHANGED
@@ -13,20 +13,19 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.homepage = "https://github.com/jsmestad/jsonapi-consumer"
|
14
14
|
spec.license = "Apache-2.0"
|
15
15
|
|
16
|
-
spec.files = `git ls-files -z`.split("\x0")
|
17
|
-
|
18
|
-
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
18
|
+
end
|
19
|
+
spec.bindir = "exe"
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
21
|
spec.require_paths = ["lib"]
|
20
22
|
|
21
|
-
spec.add_runtime_dependency "
|
22
|
-
spec.add_runtime_dependency "
|
23
|
-
spec.add_runtime_dependency "faraday", "~> 0.9.0"
|
23
|
+
spec.add_runtime_dependency "activesupport", '>= 3.2'
|
24
|
+
spec.add_runtime_dependency "faraday", '>= 0.9'
|
24
25
|
spec.add_runtime_dependency "faraday_middleware"
|
26
|
+
spec.add_runtime_dependency "addressable", '~> 2.5.2'
|
27
|
+
spec.add_runtime_dependency "activemodel", '>= 3.2'
|
25
28
|
|
26
|
-
spec.add_development_dependency "bundler", "~> 1.6"
|
27
|
-
spec.add_development_dependency "factory_girl"
|
28
|
-
spec.add_development_dependency "rake", "~> 10.0"
|
29
|
-
spec.add_development_dependency "rspec"
|
30
|
-
spec.add_development_dependency "rspec-its"
|
31
29
|
spec.add_development_dependency "webmock"
|
30
|
+
spec.add_development_dependency "mocha"
|
32
31
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module JSONAPI::Consumer
|
2
|
+
module Associations
|
3
|
+
class BaseAssociation
|
4
|
+
attr_reader :attr_name, :klass, :options
|
5
|
+
def initialize(attr_name, klass, options = {})
|
6
|
+
@attr_name = attr_name
|
7
|
+
@klass = klass
|
8
|
+
@options = options
|
9
|
+
end
|
10
|
+
|
11
|
+
def association_class
|
12
|
+
@association_class ||= Utils.compute_type(klass, options.fetch(:class_name) do
|
13
|
+
attr_name.to_s.classify
|
14
|
+
end)
|
15
|
+
end
|
16
|
+
|
17
|
+
def data(url)
|
18
|
+
from_result_set(association_class.requestor.linked(url))
|
19
|
+
end
|
20
|
+
|
21
|
+
def from_result_set(result_set)
|
22
|
+
result_set.to_a
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module JSONAPI::Consumer
|
2
|
+
module Associations
|
3
|
+
module BelongsTo
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def belongs_to(attr_name, options = {})
|
8
|
+
# self.associations = self.associations + [HasOne::Association.new(attr_name, self, options)]
|
9
|
+
self.associations += [BelongsTo::Association.new(attr_name, self, options)]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Association < BaseAssociation
|
14
|
+
include Helpers::URI
|
15
|
+
def param
|
16
|
+
:"#{attr_name}_id"
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_prefix_path(formatter)
|
20
|
+
"#{formatter.format(attr_name.to_s.pluralize)}/%{#{param}}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def set_prefix_path(attrs, formatter)
|
24
|
+
attrs[param] = encode_part(attrs[param]) if attrs.key?(param)
|
25
|
+
to_prefix_path(formatter) % attrs
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module JSONAPI::Consumer
|
2
|
+
module Associations
|
3
|
+
module HasMany
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def has_many(attr_name, options = {})
|
8
|
+
self.associations = self.associations + [HasMany::Association.new(attr_name, self, options)]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Association < BaseAssociation
|
13
|
+
def query_builder(url)
|
14
|
+
association_class.query_builder.new(
|
15
|
+
association_class,
|
16
|
+
association_class.requestor_class.new(association_class, url)
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
def data(url)
|
21
|
+
query_builder(url)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module JSONAPI::Consumer
|
2
|
+
module Associations
|
3
|
+
module HasOne
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def has_one(attr_name, options = {})
|
8
|
+
self.associations += [HasOne::Association.new(attr_name, self, options)]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Association < BaseAssociation
|
13
|
+
def from_result_set(result_set)
|
14
|
+
result_set.first
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module JSONAPI::Consumer
|
2
|
+
class Connection
|
3
|
+
|
4
|
+
attr_reader :faraday
|
5
|
+
|
6
|
+
def initialize(options = {})
|
7
|
+
site = options.fetch(:site)
|
8
|
+
connection_options = options.slice(:proxy, :ssl, :request, :headers, :params)
|
9
|
+
adapter_options = Array(options.fetch(:adapter, Faraday.default_adapter))
|
10
|
+
@faraday = Faraday.new(site, connection_options) do |builder|
|
11
|
+
builder.request :json
|
12
|
+
builder.use Middleware::JsonRequest
|
13
|
+
builder.use Middleware::Status
|
14
|
+
builder.use Middleware::ParseJson
|
15
|
+
builder.adapter(*adapter_options)
|
16
|
+
end
|
17
|
+
yield(self) if block_given?
|
18
|
+
end
|
19
|
+
|
20
|
+
# insert middleware before ParseJson - middleware executed in reverse order -
|
21
|
+
# inserted middleware will run after json parsed
|
22
|
+
def use(middleware, *args, &block)
|
23
|
+
return if faraday.builder.locked?
|
24
|
+
faraday.builder.insert_before(Middleware::ParseJson, middleware, *args, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
def delete(middleware)
|
28
|
+
faraday.builder.delete(middleware)
|
29
|
+
end
|
30
|
+
|
31
|
+
def run(request_method, path, params = {}, headers = {})
|
32
|
+
faraday.send(request_method, path, params, headers)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module JSONAPI::Consumer
|
2
|
+
class ErrorCollector < Array
|
3
|
+
class Error
|
4
|
+
delegate :[], to: :attrs
|
5
|
+
|
6
|
+
def initialize(attrs = {})
|
7
|
+
@attrs = (attrs || {}).with_indifferent_access
|
8
|
+
end
|
9
|
+
|
10
|
+
def id
|
11
|
+
attrs[:id]
|
12
|
+
end
|
13
|
+
|
14
|
+
def about
|
15
|
+
res = attrs.fetch(:links, {})
|
16
|
+
res ? res[:about] : {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def status
|
20
|
+
attrs[:status]
|
21
|
+
end
|
22
|
+
|
23
|
+
def code
|
24
|
+
attrs[:code]
|
25
|
+
end
|
26
|
+
|
27
|
+
def title
|
28
|
+
attrs[:title]
|
29
|
+
end
|
30
|
+
|
31
|
+
def detail
|
32
|
+
attrs[:detail]
|
33
|
+
end
|
34
|
+
|
35
|
+
def source_parameter
|
36
|
+
source[:parameter]
|
37
|
+
end
|
38
|
+
|
39
|
+
def source_pointer
|
40
|
+
source[:pointer]
|
41
|
+
end
|
42
|
+
|
43
|
+
def error_key
|
44
|
+
if source_pointer && source_pointer != "/data"
|
45
|
+
source_pointer.split("/").last
|
46
|
+
else
|
47
|
+
"base"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def error_msg
|
52
|
+
msg = title || detail || "invalid"
|
53
|
+
if source_parameter
|
54
|
+
"#{source_parameter} #{msg}"
|
55
|
+
else
|
56
|
+
msg
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def source
|
61
|
+
res = attrs.fetch(:source, {})
|
62
|
+
res ? res : {}
|
63
|
+
end
|
64
|
+
|
65
|
+
def meta
|
66
|
+
MetaData.new(attrs.fetch(:meta, {}))
|
67
|
+
end
|
68
|
+
|
69
|
+
protected
|
70
|
+
|
71
|
+
attr_reader :attrs
|
72
|
+
end
|
73
|
+
|
74
|
+
def initialize(error_data)
|
75
|
+
super(error_data.map do |data|
|
76
|
+
Error.new(data)
|
77
|
+
end)
|
78
|
+
end
|
79
|
+
|
80
|
+
def full_messages
|
81
|
+
map(&:title)
|
82
|
+
end
|
83
|
+
|
84
|
+
def [](source)
|
85
|
+
map do |error|
|
86
|
+
error.error_key == source
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
end
|
@@ -1,98 +1,56 @@
|
|
1
|
-
# JSONAPI::Consumer::Errors is responsible for wrapping API errors into a consistent
|
2
|
-
# form. Handling or Rescuing from these errors is left up to the client, but
|
3
|
-
# a possible way to do this is detailed below.
|
4
|
-
#
|
5
|
-
# # lib/errors/rescue_error.rb
|
6
|
-
# module Errors
|
7
|
-
# module RescueError
|
8
|
-
#
|
9
|
-
# def self.included(base)
|
10
|
-
# base.rescue_from Errors::ResponseError do |e|
|
11
|
-
# render "public/#{e.code}", :status => e.code
|
12
|
-
# end
|
13
|
-
# end
|
14
|
-
#
|
15
|
-
# end
|
16
|
-
# end
|
17
|
-
#
|
18
1
|
module JSONAPI::Consumer
|
19
2
|
module Errors
|
20
|
-
class
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
def message
|
25
|
-
'Server did not respond in a timely fashion. Is it running?'
|
3
|
+
class ApiError < StandardError
|
4
|
+
attr_reader :env
|
5
|
+
def initialize(env)
|
6
|
+
@env = env
|
26
7
|
end
|
27
8
|
end
|
28
9
|
|
29
|
-
|
30
|
-
|
31
|
-
NOT_AUTHORIZED = 401
|
32
|
-
FORBIDDEN = 403
|
33
|
-
NOT_FOUND = 404
|
34
|
-
METHOD_NOT_ALLOWED = 405
|
35
|
-
BAD_FORMAT = 406
|
36
|
-
REQUESTED_RANGE_NOT_SATISFIABLE = 416
|
37
|
-
UNPROCESSABLE_ENTITY = 422
|
38
|
-
INTERNAL_SERVER_ERROR = 500
|
10
|
+
class ClientError < ApiError
|
11
|
+
end
|
39
12
|
|
40
|
-
|
41
|
-
|
42
|
-
attr_accessor :response
|
13
|
+
class AccessDenied < ClientError
|
14
|
+
end
|
43
15
|
|
44
|
-
|
45
|
-
|
46
|
-
self.response = response
|
47
|
-
end
|
16
|
+
class NotAuthorized < ClientError
|
17
|
+
end
|
48
18
|
|
49
|
-
|
50
|
-
|
51
|
-
end
|
19
|
+
class ConnectionError < ApiError
|
20
|
+
end
|
52
21
|
|
53
|
-
|
54
|
-
|
22
|
+
class ServerError < ApiError
|
23
|
+
def message
|
24
|
+
"Internal server error"
|
55
25
|
end
|
56
26
|
end
|
57
27
|
|
58
|
-
class
|
59
|
-
|
60
|
-
|
61
|
-
def error_constants
|
62
|
-
constants.each_with_object({}) do |name, hash|
|
63
|
-
# Ignore any class constants
|
64
|
-
next if (code = Errors.const_get(name)).is_a?(Class)
|
65
|
-
hash[name] = code
|
66
|
-
end
|
28
|
+
class Conflict < ServerError
|
29
|
+
def message
|
30
|
+
"Resource already exists"
|
67
31
|
end
|
32
|
+
end
|
68
33
|
|
69
|
-
|
70
|
-
|
71
|
-
|
34
|
+
class NotFound < ServerError
|
35
|
+
attr_reader :uri
|
36
|
+
def initialize(uri)
|
37
|
+
@uri = uri
|
72
38
|
end
|
73
|
-
|
74
|
-
|
75
|
-
# Default to InternalServerError.
|
76
|
-
def class_for_error_name(name)
|
77
|
-
class_name = class_name_for_error_name(name)
|
78
|
-
const_defined?(class_name) ? Errors.const_get(class_name) : Errors::InternalServerError
|
39
|
+
def message
|
40
|
+
"Couldn't find resource at: #{uri.to_s}"
|
79
41
|
end
|
42
|
+
end
|
80
43
|
|
81
|
-
|
82
|
-
|
83
|
-
def
|
84
|
-
|
85
|
-
|
44
|
+
class UnexpectedStatus < ServerError
|
45
|
+
attr_reader :code, :uri
|
46
|
+
def initialize(code, uri)
|
47
|
+
@code = code
|
48
|
+
@uri = uri
|
49
|
+
end
|
50
|
+
def message
|
51
|
+
"Unexpected response status: #{code} from: #{uri.to_s}"
|
86
52
|
end
|
87
53
|
end
|
88
|
-
end
|
89
54
|
|
90
|
-
# Dynamically creates a subclass of ResponseError for each error constant.
|
91
|
-
# Adds a code method to return the correct response code.
|
92
|
-
# Adds the new class to the constants in the Errors module.
|
93
|
-
Errors.error_constants.each do |name, code|
|
94
|
-
klass = Class.new(Errors::ResponseError)
|
95
|
-
klass.send(:define_method, :code) { code }
|
96
|
-
Errors.const_set(Errors.class_name_for_error_name(name), klass)
|
97
55
|
end
|
98
56
|
end
|