json_api_client 0.9.6 → 1.0.0.beta
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 +4 -4
- data/README.md +274 -84
- data/lib/json_api_client.rb +9 -4
- data/lib/json_api_client/connection.rb +5 -5
- data/lib/json_api_client/error_collector.rb +29 -0
- data/lib/json_api_client/errors.rb +7 -5
- data/lib/json_api_client/helpers.rb +3 -0
- data/lib/json_api_client/helpers/associable.rb +4 -3
- data/lib/json_api_client/helpers/attributable.rb +15 -46
- data/lib/json_api_client/helpers/custom_endpoints.rb +3 -10
- data/lib/json_api_client/helpers/dynamic_attributes.rb +61 -0
- data/lib/json_api_client/helpers/linkable.rb +28 -18
- data/lib/json_api_client/helpers/paginatable.rb +13 -0
- data/lib/json_api_client/helpers/parsable.rb +1 -1
- data/lib/json_api_client/helpers/queryable.rb +4 -3
- data/lib/json_api_client/helpers/requestable.rb +60 -0
- data/lib/json_api_client/linking.rb +7 -0
- data/lib/json_api_client/linking/included_data.rb +40 -0
- data/lib/json_api_client/linking/links.rb +29 -0
- data/lib/json_api_client/linking/top_level_links.rb +30 -0
- data/lib/json_api_client/meta_data.rb +10 -0
- data/lib/json_api_client/middleware/json_request.rb +3 -4
- data/lib/json_api_client/middleware/status.rb +10 -1
- data/lib/json_api_client/paginating.rb +5 -0
- data/lib/json_api_client/paginating/paginator.rb +80 -0
- data/lib/json_api_client/parsers.rb +5 -0
- data/lib/json_api_client/parsers/parser.rb +55 -0
- data/lib/json_api_client/query.rb +2 -7
- data/lib/json_api_client/query/builder.rb +126 -0
- data/lib/json_api_client/query/requestor.rb +77 -0
- data/lib/json_api_client/resource.rb +3 -59
- data/lib/json_api_client/result_set.rb +11 -29
- data/lib/json_api_client/schema.rb +15 -30
- data/lib/json_api_client/version.rb +1 -1
- metadata +36 -19
- data/lib/json_api_client/link.rb +0 -11
- data/lib/json_api_client/link_definition.rb +0 -27
- data/lib/json_api_client/linked_data.rb +0 -75
- data/lib/json_api_client/parser.rb +0 -63
- data/lib/json_api_client/query/base.rb +0 -38
- data/lib/json_api_client/query/create.rb +0 -17
- data/lib/json_api_client/query/custom.rb +0 -22
- data/lib/json_api_client/query/destroy.rb +0 -12
- data/lib/json_api_client/query/find.rb +0 -19
- data/lib/json_api_client/query/linked.rb +0 -24
- data/lib/json_api_client/query/update.rb +0 -13
- data/lib/json_api_client/scope.rb +0 -48
@@ -6,7 +6,7 @@ module JsonApiClient
|
|
6
6
|
def initialize(options = {})
|
7
7
|
site = options.fetch(:site)
|
8
8
|
@faraday = Faraday.new(site) do |builder|
|
9
|
-
builder.request :
|
9
|
+
builder.request :json
|
10
10
|
builder.use Middleware::JsonRequest
|
11
11
|
builder.use Middleware::Status
|
12
12
|
builder.use Middleware::ParseJson
|
@@ -15,7 +15,7 @@ module JsonApiClient
|
|
15
15
|
yield(self) if block_given?
|
16
16
|
end
|
17
17
|
|
18
|
-
# insert middleware before ParseJson - middleware executed in reverse order -
|
18
|
+
# insert middleware before ParseJson - middleware executed in reverse order -
|
19
19
|
# inserted middleware will run after json parsed
|
20
20
|
def use(middleware, *args, &block)
|
21
21
|
return if faraday.builder.locked?
|
@@ -26,9 +26,9 @@ module JsonApiClient
|
|
26
26
|
faraday.builder.delete(middleware)
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
30
|
-
faraday.send(
|
29
|
+
def run(request_method, path, params = {}, headers = {})
|
30
|
+
faraday.send(request_method, path, params, headers)
|
31
31
|
end
|
32
32
|
|
33
33
|
end
|
34
|
-
end
|
34
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module JsonApiClient
|
2
|
+
class ErrorCollector
|
3
|
+
class Error
|
4
|
+
include Helpers::DynamicAttributes
|
5
|
+
|
6
|
+
def initialize(attrs = {})
|
7
|
+
attrs = {
|
8
|
+
title: attrs
|
9
|
+
} if attrs.is_a?(String)
|
10
|
+
self.attributes = attrs
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
attr_reader :errors
|
15
|
+
extend Forwardable
|
16
|
+
def_delegators :errors, :length, :present?
|
17
|
+
|
18
|
+
def initialize(error_data)
|
19
|
+
@errors = Array(error_data).map do |datum|
|
20
|
+
Error.new(datum)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def full_messages
|
25
|
+
errors.map(&:title)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -10,13 +10,15 @@ module JsonApiClient
|
|
10
10
|
class ClientError < ApiError
|
11
11
|
end
|
12
12
|
|
13
|
+
class AccessDenied < ClientError
|
14
|
+
end
|
15
|
+
|
16
|
+
class ConnectionError < ApiError
|
17
|
+
end
|
18
|
+
|
13
19
|
class ServerError < ApiError
|
14
|
-
attr_reader :uri
|
15
|
-
def initialize(uri)
|
16
|
-
@uri = uri
|
17
|
-
end
|
18
20
|
def message
|
19
|
-
"Internal server error
|
21
|
+
"Internal server error"
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
@@ -3,10 +3,13 @@ module JsonApiClient
|
|
3
3
|
autoload :Associable, 'json_api_client/helpers/associable'
|
4
4
|
autoload :Attributable, 'json_api_client/helpers/attributable'
|
5
5
|
autoload :CustomEndpoints, 'json_api_client/helpers/custom_endpoints'
|
6
|
+
autoload :DynamicAttributes, 'json_api_client/helpers/dynamic_attributes'
|
6
7
|
autoload :Initializable, 'json_api_client/helpers/initializable'
|
7
8
|
autoload :Linkable, 'json_api_client/helpers/linkable'
|
9
|
+
autoload :Paginatable, 'json_api_client/helpers/paginatable'
|
8
10
|
autoload :Parsable, 'json_api_client/helpers/parsable'
|
9
11
|
autoload :Queryable, 'json_api_client/helpers/queryable'
|
12
|
+
autoload :Requestable, 'json_api_client/helpers/requestable'
|
10
13
|
autoload :Schemable, 'json_api_client/helpers/schemable'
|
11
14
|
autoload :Serializable, 'json_api_client/helpers/serializable'
|
12
15
|
end
|
@@ -30,11 +30,12 @@ module JsonApiClient
|
|
30
30
|
def path(params = nil)
|
31
31
|
parts = [table_name]
|
32
32
|
if params
|
33
|
-
|
33
|
+
filters = params.fetch(:filter, params)
|
34
|
+
slurp = filters.slice(*prefix_params)
|
34
35
|
prefix_params.each do |param|
|
35
|
-
|
36
|
+
filters.delete(param)
|
36
37
|
end
|
37
|
-
parts.unshift(prefix_path % slurp)
|
38
|
+
parts.unshift(prefix_path % slurp.symbolize_keys)
|
38
39
|
else
|
39
40
|
parts.unshift(prefix_path)
|
40
41
|
end
|
@@ -4,19 +4,22 @@ module JsonApiClient
|
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
6
|
included do
|
7
|
-
|
7
|
+
include DynamicAttributes
|
8
8
|
attr_accessor :errors
|
9
9
|
initializer do |obj, params|
|
10
|
-
obj.attributes = params
|
10
|
+
obj.attributes = params.merge(obj.class.default_attributes)
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
|
15
|
-
|
14
|
+
module ClassMethods
|
15
|
+
def load(params)
|
16
|
+
new(params).tap do |resource|
|
17
|
+
resource.mark_as_persisted!
|
18
|
+
end
|
19
|
+
end
|
16
20
|
|
17
|
-
|
18
|
-
|
19
|
-
set_attribute(key, value)
|
21
|
+
def default_attributes
|
22
|
+
{type: table_name}
|
20
23
|
end
|
21
24
|
end
|
22
25
|
|
@@ -25,8 +28,12 @@ module JsonApiClient
|
|
25
28
|
save
|
26
29
|
end
|
27
30
|
|
31
|
+
def mark_as_persisted!
|
32
|
+
@persisted = true
|
33
|
+
end
|
34
|
+
|
28
35
|
def persisted?
|
29
|
-
|
36
|
+
!!@persisted && has_attribute?(primary_key)
|
30
37
|
end
|
31
38
|
|
32
39
|
def query_params
|
@@ -37,46 +44,8 @@ module JsonApiClient
|
|
37
44
|
attributes.fetch(primary_key, "").to_s
|
38
45
|
end
|
39
46
|
|
40
|
-
def [](key)
|
41
|
-
read_attribute(key)
|
42
|
-
end
|
43
|
-
|
44
|
-
def []=(key, value)
|
45
|
-
set_attribute(key, value)
|
46
|
-
end
|
47
|
-
|
48
|
-
def respond_to?(method, include_private = false)
|
49
|
-
if (method.to_s =~ /^(.*)=$/) || has_attribute?(method)
|
50
|
-
true
|
51
|
-
else
|
52
|
-
super
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
47
|
protected
|
57
48
|
|
58
|
-
def method_missing(method, *args, &block)
|
59
|
-
if method.to_s =~ /^(.*)=$/
|
60
|
-
set_attribute($1, args.first)
|
61
|
-
elsif has_attribute?(method)
|
62
|
-
attributes[method]
|
63
|
-
else
|
64
|
-
super
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def read_attribute(name)
|
69
|
-
attributes.fetch(name, nil)
|
70
|
-
end
|
71
|
-
|
72
|
-
def set_attribute(name, value)
|
73
|
-
attributes[name] = value
|
74
|
-
end
|
75
|
-
|
76
|
-
def has_attribute?(attr_name)
|
77
|
-
attributes.has_key?(attr_name)
|
78
|
-
end
|
79
|
-
|
80
49
|
def ==(other)
|
81
50
|
self.class == other.class && attributes == other.attributes
|
82
51
|
end
|
@@ -18,11 +18,8 @@ module JsonApiClient
|
|
18
18
|
end
|
19
19
|
metaclass.instance_eval do
|
20
20
|
define_method(name) do |*params|
|
21
|
-
|
22
|
-
|
23
|
-
params: request_params = params.first || {}
|
24
|
-
}.merge(options)
|
25
|
-
run_request(Query::Custom.new(self, input))
|
21
|
+
request_params = params.first || {}
|
22
|
+
requestor.custom(name, options, request_params)
|
26
23
|
end
|
27
24
|
end
|
28
25
|
end
|
@@ -31,11 +28,7 @@ module JsonApiClient
|
|
31
28
|
define_method name do |*params|
|
32
29
|
request_params = params.first || {}
|
33
30
|
request_params[self.class.primary_key] = attributes.fetch(primary_key)
|
34
|
-
|
35
|
-
name: name,
|
36
|
-
params: request_params
|
37
|
-
}.merge(options)
|
38
|
-
run_request(Query::Custom.new(self.class, input))
|
31
|
+
self.class.requestor.custom(name, options, request_params)
|
39
32
|
end
|
40
33
|
end
|
41
34
|
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module JsonApiClient
|
2
|
+
module Helpers
|
3
|
+
module DynamicAttributes
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def attributes
|
7
|
+
@attributes
|
8
|
+
end
|
9
|
+
|
10
|
+
def attributes=(attrs = {})
|
11
|
+
@attributes ||= {}.with_indifferent_access
|
12
|
+
|
13
|
+
return @attributes unless attrs.present?
|
14
|
+
attrs.each do |key, value|
|
15
|
+
set_attribute(key, value)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def [](key)
|
20
|
+
read_attribute(key)
|
21
|
+
end
|
22
|
+
|
23
|
+
def []=(key, value)
|
24
|
+
set_attribute(key, value)
|
25
|
+
end
|
26
|
+
|
27
|
+
def respond_to_missing?(method, include_private = false)
|
28
|
+
if (method.to_s =~ /^(.*)=$/) || has_attribute?(method)
|
29
|
+
true
|
30
|
+
else
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def has_attribute?(attr_name)
|
36
|
+
attributes.has_key?(attr_name)
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
def method_missing(method, *args, &block)
|
42
|
+
if method.to_s =~ /^(.*)=$/
|
43
|
+
set_attribute($1, args.first)
|
44
|
+
elsif has_attribute?(method)
|
45
|
+
attributes[method]
|
46
|
+
else
|
47
|
+
super
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def read_attribute(name)
|
52
|
+
attributes.fetch(name, nil)
|
53
|
+
end
|
54
|
+
|
55
|
+
def set_attribute(name, value)
|
56
|
+
attributes[name] = value
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -4,35 +4,45 @@ module JsonApiClient
|
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
6
|
included do
|
7
|
-
|
8
|
-
|
7
|
+
class_attribute :linker
|
8
|
+
self.linker = Linking::Links
|
9
|
+
|
10
|
+
# the links for this resource
|
11
|
+
attr_accessor :links
|
12
|
+
|
13
|
+
# reference to all of the preloaded data
|
14
|
+
attr_accessor :linked_data
|
9
15
|
|
10
16
|
initializer do |obj, params|
|
11
|
-
|
12
|
-
|
13
|
-
|
17
|
+
links = params && params.delete("links")
|
18
|
+
links ||= {}
|
19
|
+
obj.links = obj.linker.new(links)
|
14
20
|
end
|
15
21
|
end
|
16
22
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
|
23
|
+
def as_link
|
24
|
+
{
|
25
|
+
:type => self.class.table_name,
|
26
|
+
primary_key => self[primary_key]
|
27
|
+
}
|
21
28
|
end
|
22
29
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
30
|
+
def attributes
|
31
|
+
super.tap do |attrs|
|
32
|
+
attrs.merge!(links: links.attributes) if links.present?
|
33
|
+
end
|
26
34
|
end
|
27
35
|
|
28
|
-
|
36
|
+
def method_missing(method, *args)
|
37
|
+
return super unless links && links.has_attribute?(method)
|
38
|
+
linked_data.data_for(method, links[method])
|
39
|
+
end
|
29
40
|
|
30
|
-
def
|
31
|
-
links &&
|
32
|
-
|
33
|
-
linked_data &&
|
34
|
-
linked_data.has_link?(symbol.to_s)
|
41
|
+
def respond_to_missing?(symbol, include_all = false)
|
42
|
+
return true if links && links.has_attribute?(symbol)
|
43
|
+
super
|
35
44
|
end
|
45
|
+
|
36
46
|
end
|
37
47
|
end
|
38
48
|
end
|
@@ -6,16 +6,17 @@ module JsonApiClient
|
|
6
6
|
included do
|
7
7
|
class << self
|
8
8
|
extend Forwardable
|
9
|
-
def_delegators :new_scope, :where, :order, :includes, :all, :paginate, :page, :first
|
9
|
+
def_delegators :new_scope, :where, :order, :includes, :select, :all, :paginate, :page, :first
|
10
10
|
end
|
11
|
-
class_attribute :connection_class, :connection_object, :connection_options
|
11
|
+
class_attribute :connection_class, :connection_object, :connection_options, :query_builder
|
12
12
|
self.connection_class = Connection
|
13
13
|
self.connection_options = {}
|
14
|
+
self.query_builder = Query::Builder
|
14
15
|
end
|
15
16
|
|
16
17
|
module ClassMethods
|
17
18
|
def new_scope
|
18
|
-
|
19
|
+
query_builder.new(self)
|
19
20
|
end
|
20
21
|
|
21
22
|
def connection(&block)
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module JsonApiClient
|
2
|
+
module Helpers
|
3
|
+
module Requestable
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
attr_accessor :last_result_set, :errors
|
8
|
+
class_attribute :requestor_class
|
9
|
+
self.requestor_class = Query::Requestor
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
def find(conditions)
|
14
|
+
requestor.find(conditions)
|
15
|
+
end
|
16
|
+
|
17
|
+
def create(conditions = {})
|
18
|
+
new(conditions).tap do |resource|
|
19
|
+
resource.save
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def requestor
|
24
|
+
@requestor ||= requestor_class.new(self)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def save
|
29
|
+
self.last_result_set = if persisted?
|
30
|
+
self.class.requestor.update(self)
|
31
|
+
else
|
32
|
+
self.class.requestor.create(self)
|
33
|
+
end
|
34
|
+
|
35
|
+
if last_result_set.has_errors?
|
36
|
+
self.errors = last_result_set.errors
|
37
|
+
false
|
38
|
+
else
|
39
|
+
self.errors.clear if self.errors
|
40
|
+
mark_as_persisted!
|
41
|
+
if updated = last_result_set.first
|
42
|
+
self.attributes = updated.attributes
|
43
|
+
end
|
44
|
+
true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def destroy
|
49
|
+
self.last_result_set = self.class.requestor.destroy(self)
|
50
|
+
if !last_result_set.has_errors?
|
51
|
+
self.attributes.clear
|
52
|
+
true
|
53
|
+
else
|
54
|
+
false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|