json_api_client 0.9.6 → 1.0.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- 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
|