jsonapi-consumer 0.1.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
[![
|
5
|
+
[![CircleCI](https://circleci.com/gh/jsmestad/jsonapi-consumer.svg?style=svg)](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
|