munson 0.2.0 → 0.3.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 +4 -4
- data/README.md +234 -246
- data/bin/console +2 -10
- data/lib/munson/agent.rb +35 -69
- data/lib/munson/attribute.rb +76 -0
- data/lib/munson/client.rb +43 -0
- data/lib/munson/collection.rb +19 -1
- data/lib/munson/connection.rb +61 -14
- data/lib/munson/document.rb +140 -0
- data/lib/munson/key_formatter.rb +87 -0
- data/lib/munson/middleware/encode_json_api.rb +10 -2
- data/lib/munson/middleware/json_parser.rb +11 -5
- data/lib/munson/query.rb +218 -0
- data/lib/munson/resource.rb +174 -20
- data/lib/munson/response_mapper.rb +92 -32
- data/lib/munson/version.rb +1 -1
- data/lib/munson.rb +30 -22
- metadata +7 -7
- data/lib/munson/model.rb +0 -15
- data/lib/munson/paginator/offset_paginator.rb +0 -45
- data/lib/munson/paginator/paged_paginator.rb +0 -47
- data/lib/munson/paginator.rb +0 -6
- data/lib/munson/query_builder.rb +0 -226
@@ -4,7 +4,12 @@ module Munson
|
|
4
4
|
CONTENT_TYPE = 'Content-Type'.freeze
|
5
5
|
ACCEPT = 'Accept'.freeze
|
6
6
|
MIME_TYPE = 'application/vnd.api+json'.freeze
|
7
|
-
USER_AGENT = 'User-Agent'
|
7
|
+
USER_AGENT = 'User-Agent'.freeze
|
8
|
+
|
9
|
+
def initialize(app, key_formatter = nil)
|
10
|
+
super(app)
|
11
|
+
@key_formatter = key_formatter
|
12
|
+
end
|
8
13
|
|
9
14
|
def call(env)
|
10
15
|
env[:request_headers][USER_AGENT] = "Munson v#{Munson::VERSION}"
|
@@ -16,7 +21,8 @@ module Munson
|
|
16
21
|
end
|
17
22
|
|
18
23
|
def encode(data)
|
19
|
-
|
24
|
+
json = @key_formatter ? @key_formatter.externalize(data) : data
|
25
|
+
::JSON.dump(json)
|
20
26
|
end
|
21
27
|
|
22
28
|
def match_content_type(env)
|
@@ -43,3 +49,5 @@ module Munson
|
|
43
49
|
end
|
44
50
|
end
|
45
51
|
end
|
52
|
+
|
53
|
+
Faraday::Request.register_middleware :"Munson::Middleware::EncodeJsonApi" => Munson::Middleware::EncodeJsonApi
|
@@ -1,10 +1,14 @@
|
|
1
1
|
module Munson
|
2
2
|
module Middleware
|
3
|
-
class JsonParser < Faraday::Middleware
|
3
|
+
class JsonParser < Faraday::Response::Middleware
|
4
|
+
def initialize(app, key_formatter = nil)
|
5
|
+
super(app)
|
6
|
+
@key_formatter = key_formatter
|
7
|
+
end
|
8
|
+
|
4
9
|
def call(request_env)
|
5
|
-
@app.call(request_env).on_complete do |
|
6
|
-
|
7
|
-
response_env[:body] = parse(response_env[:body])
|
10
|
+
@app.call(request_env).on_complete do |request_env|
|
11
|
+
request_env[:body] = parse(request_env[:body])
|
8
12
|
end
|
9
13
|
end
|
10
14
|
|
@@ -12,7 +16,8 @@ module Munson
|
|
12
16
|
|
13
17
|
def parse(body)
|
14
18
|
unless body.strip.empty?
|
15
|
-
::JSON.parse(body, symbolize_names: true)
|
19
|
+
json = ::JSON.parse(body, symbolize_names: true)
|
20
|
+
@key_formatter ? @key_formatter.internalize(json) : json
|
16
21
|
else
|
17
22
|
{}
|
18
23
|
end
|
@@ -20,3 +25,4 @@ module Munson
|
|
20
25
|
end
|
21
26
|
end
|
22
27
|
end
|
28
|
+
Faraday::Response.register_middleware :"Munson::Middleware::JsonParser" => Munson::Middleware::JsonParser
|
data/lib/munson/query.rb
ADDED
@@ -0,0 +1,218 @@
|
|
1
|
+
module Munson
|
2
|
+
class Query
|
3
|
+
attr_reader :values
|
4
|
+
|
5
|
+
# Description of method
|
6
|
+
#
|
7
|
+
# @param [Munson::Client] client
|
8
|
+
def initialize(client = nil)
|
9
|
+
@client = client
|
10
|
+
@headers = {}
|
11
|
+
@values = {
|
12
|
+
include: [],
|
13
|
+
fields: [],
|
14
|
+
filter: [],
|
15
|
+
sort: [],
|
16
|
+
page: {}
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def fetch
|
21
|
+
if @client
|
22
|
+
response = @client.agent.get(params: to_params, headers: @headers)
|
23
|
+
ResponseMapper.new(response.body).collection
|
24
|
+
else
|
25
|
+
raise Munson::ClientNotSet, "Client was not set. Query#new(client)"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def find(id)
|
30
|
+
if @client
|
31
|
+
response = @client.agent.get(id: id, params: to_params, headers: @headers)
|
32
|
+
ResponseMapper.new(response.body).resource
|
33
|
+
else
|
34
|
+
raise Munson::ClientNotSet, "Client was not set. Query#new(client)"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# @return [String] query as a query string
|
39
|
+
def to_query_string
|
40
|
+
Faraday::Utils.build_nested_query(to_params)
|
41
|
+
end
|
42
|
+
|
43
|
+
def to_s
|
44
|
+
to_query_string
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_params
|
48
|
+
str = {}
|
49
|
+
str[:filter] = filter_to_query_value unless @values[:filter].empty?
|
50
|
+
str[:fields] = fields_to_query_value unless @values[:fields].empty?
|
51
|
+
str[:include] = include_to_query_value unless @values[:include].empty?
|
52
|
+
str[:sort] = sort_to_query_value unless @values[:sort].empty?
|
53
|
+
str[:page] = @values[:page] unless @values[:page].empty?
|
54
|
+
str
|
55
|
+
end
|
56
|
+
|
57
|
+
# Chainably set page options
|
58
|
+
#
|
59
|
+
# @example set a limit and offset
|
60
|
+
# Munson::Query.new.page(limit: 10, offset: 5)
|
61
|
+
#
|
62
|
+
# @example set a size and number
|
63
|
+
# Munson::Query.new.page(size: 10, number: 5)
|
64
|
+
#
|
65
|
+
# @return [Munson::Query] self for chaining queries
|
66
|
+
def page(opts={})
|
67
|
+
@values[:page].merge!(opts)
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
# Chainably set headers
|
72
|
+
#
|
73
|
+
# @example set a header
|
74
|
+
# Munson::Query.new.headers("X-API-TOKEN" => "banana")
|
75
|
+
#
|
76
|
+
# @example set headers
|
77
|
+
# Munson::Query.new.headers("X-API-TOKEN" => "banana", "X-API-VERSION" => "1.3")
|
78
|
+
#
|
79
|
+
# @return [Munson::Query] self for chaining queries
|
80
|
+
def headers(opts={})
|
81
|
+
@headers.merge!(opts)
|
82
|
+
self
|
83
|
+
end
|
84
|
+
|
85
|
+
# Chainably include related resources.
|
86
|
+
#
|
87
|
+
# @example including a resource
|
88
|
+
# Munson::Query.new.include(:user)
|
89
|
+
#
|
90
|
+
# @example including a related resource
|
91
|
+
# Munson::Query.new.include("user.addresses")
|
92
|
+
#
|
93
|
+
# @example including multiple resources
|
94
|
+
# Munson::Query.new.include("user.addresses", "user.images")
|
95
|
+
#
|
96
|
+
# @param [Array<String,Symbol>] *args relationships to include
|
97
|
+
# @return [Munson::Query] self for chaining queries
|
98
|
+
#
|
99
|
+
# @see http://jsonapi.org/format/#fetching-includes JSON API Including Relationships
|
100
|
+
def include(*args)
|
101
|
+
@values[:include] += args
|
102
|
+
self
|
103
|
+
end
|
104
|
+
|
105
|
+
# Chainably sort results
|
106
|
+
# @note Default order is ascending
|
107
|
+
#
|
108
|
+
# @example sorting by a single field
|
109
|
+
# Munsun::Query.new.sort(:created_at)
|
110
|
+
#
|
111
|
+
# @example sorting by a multiple fields
|
112
|
+
# Munsun::Query.new.sort(:created_at, :age)
|
113
|
+
#
|
114
|
+
# @example specifying sort direction
|
115
|
+
# Munsun::Query.new.sort(:created_at, age: :desc)
|
116
|
+
#
|
117
|
+
# @example specifying sort direction
|
118
|
+
# Munsun::Query.new.sort(score: :desc, :created_at)
|
119
|
+
#
|
120
|
+
# @param [Hash<Symbol,Symbol>, Symbol] *args fields to sort by
|
121
|
+
# @return [Munson::Query] self for chaining queries
|
122
|
+
#
|
123
|
+
# @see http://jsonapi.org/format/#fetching-sorting JSON API Sorting Spec
|
124
|
+
def sort(*args)
|
125
|
+
validate_sort_args(args.select{|arg| arg.is_a?(Hash)})
|
126
|
+
@values[:sort] += args
|
127
|
+
self
|
128
|
+
end
|
129
|
+
|
130
|
+
# Hash resouce_name: [array of attribs]
|
131
|
+
def fields(*args)
|
132
|
+
@values[:fields] += args
|
133
|
+
self
|
134
|
+
end
|
135
|
+
|
136
|
+
def filter(*args)
|
137
|
+
@values[:filter] += args
|
138
|
+
self
|
139
|
+
end
|
140
|
+
|
141
|
+
protected
|
142
|
+
|
143
|
+
def sort_to_query_value
|
144
|
+
@values[:sort].map{|item|
|
145
|
+
if item.is_a?(Hash)
|
146
|
+
item.to_a.map{|name,dir|
|
147
|
+
dir.to_sym == :desc ? "-#{name}" : name.to_s
|
148
|
+
}
|
149
|
+
else
|
150
|
+
item.to_s
|
151
|
+
end
|
152
|
+
}.join(',')
|
153
|
+
end
|
154
|
+
|
155
|
+
def fields_to_query_value
|
156
|
+
@values[:fields].inject({}) do |acc, hash_arg|
|
157
|
+
hash_arg.each do |k,v|
|
158
|
+
acc[k] ||= []
|
159
|
+
v.is_a?(Array) ?
|
160
|
+
acc[k] += v :
|
161
|
+
acc[k] << v
|
162
|
+
|
163
|
+
acc[k].map(&:to_s).uniq!
|
164
|
+
end
|
165
|
+
|
166
|
+
acc
|
167
|
+
end.map { |k, v| [k, v.join(',')] }.to_h
|
168
|
+
end
|
169
|
+
|
170
|
+
def include_to_query_value
|
171
|
+
@values[:include].map(&:to_s).sort.join(',')
|
172
|
+
end
|
173
|
+
|
174
|
+
# Since the filter param's format isn't specified in the [spec](http://jsonapi.org/format/#fetching-filtering)
|
175
|
+
# this implemenation uses (JSONAPI::Resource's implementation](https://github.com/cerebris/jsonapi-resources#filters)
|
176
|
+
#
|
177
|
+
# To override, implement your own CustomQuery inheriting from {Munson::Query}
|
178
|
+
# {Munson::Client} takes a Query class to use. This method could be overriden in your custom class
|
179
|
+
#
|
180
|
+
# @example Custom Query Builder
|
181
|
+
# class MyBuilder < Munson::Query
|
182
|
+
# def filter_to_query_value
|
183
|
+
# # ... your fancier logic
|
184
|
+
# end
|
185
|
+
# end
|
186
|
+
#
|
187
|
+
# class Article
|
188
|
+
# def self.munson
|
189
|
+
# return @munson if @munson
|
190
|
+
# @munson = Munson::Client.new(
|
191
|
+
# query_builder: MyQuery,
|
192
|
+
# path: 'products'
|
193
|
+
# )
|
194
|
+
# end
|
195
|
+
# end
|
196
|
+
#
|
197
|
+
def filter_to_query_value
|
198
|
+
@values[:filter].reduce({}) do |acc, hash_arg|
|
199
|
+
hash_arg.each do |k,v|
|
200
|
+
acc[k] ||= []
|
201
|
+
v.is_a?(Array) ? acc[k] += v : acc[k] << v
|
202
|
+
acc[k].uniq!
|
203
|
+
end
|
204
|
+
acc
|
205
|
+
end.map { |k, v| [k, v.join(',')] }.to_h
|
206
|
+
end
|
207
|
+
|
208
|
+
def validate_sort_args(hashes)
|
209
|
+
hashes.each do |hash|
|
210
|
+
hash.each do |k,v|
|
211
|
+
if !%i(desc asc).include?(v.to_sym)
|
212
|
+
raise Munson::UnsupportedSortDirectionError, "Unknown direction '#{v}'. Use :asc or :desc"
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
data/lib/munson/resource.rb
CHANGED
@@ -1,28 +1,182 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
class Munson::Resource
|
2
|
+
extend Forwardable
|
3
|
+
attr_reader :document
|
4
|
+
attr_reader :attributes
|
5
|
+
|
6
|
+
# @example Given a Munson::Document
|
7
|
+
# document = Munson::Document.new(jsonapi_hash)
|
8
|
+
# Person.new(document)
|
9
|
+
#
|
10
|
+
# @example Given an attributes hash
|
11
|
+
# Person.new(first_name: "Chauncy", last_name: "Vünderboot")
|
12
|
+
#
|
13
|
+
# @param [Hash,Munson::Document] attrs
|
14
|
+
def initialize(attrs = {})
|
15
|
+
if attrs.is_a?(Munson::Document)
|
16
|
+
@document = attrs
|
17
|
+
else
|
18
|
+
@document = Munson::Document.new(
|
19
|
+
data: {
|
20
|
+
type: self.class.type,
|
21
|
+
id: attrs.delete(:id),
|
22
|
+
attributes: attrs
|
23
|
+
}
|
24
|
+
)
|
5
25
|
end
|
6
26
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
27
|
+
initialize_attrs
|
28
|
+
end
|
29
|
+
|
30
|
+
def id
|
31
|
+
return nil if document.id.nil?
|
32
|
+
@id ||= self.class.format_id(document.id)
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize_attrs
|
36
|
+
@attributes = @document.attributes.clone
|
37
|
+
self.class.schema.each do |name, attribute|
|
38
|
+
casted_value = attribute.process(@attributes[name])
|
39
|
+
@attributes[name] = casted_value
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def persisted?
|
44
|
+
!id.nil?
|
45
|
+
end
|
46
|
+
|
47
|
+
def save
|
48
|
+
@document = document.save(agent)
|
49
|
+
!errors?
|
50
|
+
end
|
51
|
+
|
52
|
+
# @return [Array<Hash>] array of JSON API errors
|
53
|
+
def errors
|
54
|
+
document.errors
|
55
|
+
end
|
56
|
+
|
57
|
+
def errors?
|
58
|
+
document.errors.any?
|
59
|
+
end
|
60
|
+
|
61
|
+
# @return [Munson::Agent] a new {Munson::Agent} instance
|
62
|
+
def agent
|
63
|
+
self.class.munson.agent
|
64
|
+
end
|
65
|
+
|
66
|
+
def serialized_attributes
|
67
|
+
serialized_attrs = {}
|
68
|
+
self.class.schema.each do |name, attribute|
|
69
|
+
serialized_value = attribute.serialize(@attributes[name])
|
70
|
+
serialized_attrs[name] = serialized_value
|
71
|
+
end
|
72
|
+
serialized_attrs
|
73
|
+
end
|
74
|
+
|
75
|
+
def ==(other)
|
76
|
+
self.class.type == other.class.type && self.id == other.id
|
77
|
+
end
|
78
|
+
|
79
|
+
class << self
|
80
|
+
def inherited(subclass)
|
81
|
+
if subclass.to_s.respond_to?(:tableize)
|
82
|
+
subclass.type = subclass.to_s.tableize.to_sym
|
17
83
|
end
|
84
|
+
end
|
18
85
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
86
|
+
def key_type(type)
|
87
|
+
@key_type = type
|
88
|
+
end
|
89
|
+
|
90
|
+
def format_id(id)
|
91
|
+
case @key_type
|
92
|
+
when :integer, nil
|
93
|
+
id.to_i
|
94
|
+
when :string
|
95
|
+
id.to_s
|
96
|
+
when Proc
|
97
|
+
@key_type.call(id)
|
25
98
|
end
|
26
99
|
end
|
100
|
+
|
101
|
+
def schema
|
102
|
+
@schema ||= {}
|
103
|
+
end
|
104
|
+
|
105
|
+
def attribute(attribute_name, cast_type, **options)
|
106
|
+
schema[attribute_name] = Munson::Attribute.new(attribute_name, cast_type, options)
|
107
|
+
|
108
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
109
|
+
def #{attribute_name}
|
110
|
+
@attributes[:#{attribute_name}]
|
111
|
+
end
|
112
|
+
RUBY
|
113
|
+
|
114
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
115
|
+
def #{attribute_name}=(val)
|
116
|
+
document.attributes[:#{attribute_name}] = self.class.schema[:#{attribute_name}].serialize(val)
|
117
|
+
@attributes[:#{attribute_name}] = val
|
118
|
+
end
|
119
|
+
RUBY
|
120
|
+
end
|
121
|
+
|
122
|
+
def has_one(relation_name)
|
123
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
124
|
+
def #{relation_name}
|
125
|
+
return @_#{relation_name}_relationship if @_#{relation_name}_relationship
|
126
|
+
related_document = document.relationship(:#{relation_name})
|
127
|
+
@_#{relation_name}_relationship = Munson.factory(related_document)
|
128
|
+
end
|
129
|
+
RUBY
|
130
|
+
end
|
131
|
+
|
132
|
+
def has_many(relation_name)
|
133
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
134
|
+
def #{relation_name}
|
135
|
+
return @_#{relation_name}_relationship if @_#{relation_name}_relationship
|
136
|
+
documents = document.relationship(:#{relation_name})
|
137
|
+
collection = Munson::Collection.new(documents.map{ |doc| Munson.factory(doc) })
|
138
|
+
@_#{relation_name}_relationship = collection
|
139
|
+
end
|
140
|
+
RUBY
|
141
|
+
end
|
142
|
+
|
143
|
+
def munson_initializer(document)
|
144
|
+
new(document)
|
145
|
+
end
|
146
|
+
|
147
|
+
def munson
|
148
|
+
return @munson if @munson
|
149
|
+
@munson = Munson::Client.new
|
150
|
+
@munson
|
151
|
+
end
|
152
|
+
|
153
|
+
# Set the JSONAPI type
|
154
|
+
def type=(type)
|
155
|
+
Munson.register_type(type, self)
|
156
|
+
munson.type = type
|
157
|
+
end
|
158
|
+
|
159
|
+
# Get the JSONAPI type
|
160
|
+
def type
|
161
|
+
munson.type
|
162
|
+
end
|
163
|
+
|
164
|
+
# Overwrite Connection#fields delegator to allow for passing an array of fields
|
165
|
+
# @example
|
166
|
+
# Cat.fields(:name, :favorite_toy) #=> Query(fields[cats]=name,favorite_toy)
|
167
|
+
# Cat.fields(name, owner: [:name]) #=> Query(fields[cats]=name&fields[people]=name)
|
168
|
+
def fields(*args)
|
169
|
+
hash_fields = args.last.is_a?(Hash) ? args.pop : {}
|
170
|
+
hash_fields[type] = args if args.any?
|
171
|
+
munson.fields(hash_fields)
|
172
|
+
end
|
173
|
+
|
174
|
+
[:include, :sort, :filter, :fetch, :find, :page].each do |method|
|
175
|
+
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
176
|
+
def #{method}(*args)
|
177
|
+
munson.#{method}(*args)
|
178
|
+
end
|
179
|
+
RUBY
|
180
|
+
end
|
27
181
|
end
|
28
182
|
end
|
@@ -1,54 +1,114 @@
|
|
1
1
|
module Munson
|
2
|
+
# Maps JSONAPI Responses to ruby objects.
|
3
|
+
#
|
4
|
+
# @note
|
5
|
+
# When a JSONAPI collection (data: <Array>) is received it maps the response
|
6
|
+
# into multiple JSONAPI resource objects (data: <Hash>) and passes each to the #initialize_resource method
|
7
|
+
# so that each resource can act independently of the collection. JSONAPI collection are wrapped in a Munson::Collection
|
8
|
+
# which will also contain metadata from the request
|
9
|
+
#
|
10
|
+
# @example Mapping an unregistered JSONAPI collection response
|
11
|
+
# json = {
|
12
|
+
# data: [
|
13
|
+
# {id: 1, type: :cats, attributes: {name: 'Gorbypuff'}},
|
14
|
+
# {id: 1, type: :cats, attributes: {name: 'Grumpy Cat'}}
|
15
|
+
# ]
|
16
|
+
# }
|
17
|
+
#
|
18
|
+
# mapper = ResponseMapper.new(json)
|
19
|
+
# mapper.collection #=>
|
20
|
+
# Munson::Collection([
|
21
|
+
# {data: {id: 1, type: :cats, attributes: {name: 'Gorbypuff'}}},
|
22
|
+
# {data: {id: 1, type: :cats, attributes: {name: 'Grumpy Cat'}}
|
23
|
+
# ])
|
24
|
+
#
|
25
|
+
# @example Mapping a registered JSONAPI collection response
|
26
|
+
# json = {
|
27
|
+
# data: [
|
28
|
+
# {id: 1, type: :cats, attributes: {name: 'Gorbypuff'}},
|
29
|
+
# {id: 1, type: :cats, attributes: {name: 'Grumpy Cat'}}
|
30
|
+
# ]
|
31
|
+
# }
|
32
|
+
# class Cat
|
33
|
+
# #... munson config
|
34
|
+
# def self.munson_initializer(resource)
|
35
|
+
# Cat.new(resource)
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# def new(attribs)
|
39
|
+
# #do what you want
|
40
|
+
# end
|
41
|
+
# end
|
42
|
+
# Munson.register_type(:cats, Cat)
|
43
|
+
#
|
44
|
+
# mapper.collection #=> Munson::Collection([cat1, cat2])
|
45
|
+
#
|
46
|
+
# ResourceMapper maps responses in 3 ways:
|
47
|
+
# @example Mapping a Munson::Resource
|
48
|
+
#
|
49
|
+
# @example Mapping a registered type
|
50
|
+
#
|
51
|
+
# @example Mapping an unregistered type
|
52
|
+
#
|
2
53
|
class ResponseMapper
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
@data = response.body[:data]
|
7
|
-
@includes = response.body[:include]
|
54
|
+
# @param [Hash] response_body jsonapi formatted hash
|
55
|
+
def initialize(response_body)
|
56
|
+
@body = response_body
|
8
57
|
end
|
9
58
|
|
10
|
-
|
11
|
-
|
12
|
-
|
59
|
+
# Moved top level keys to the collection
|
60
|
+
# * errors: an array of error objects
|
61
|
+
# * meta: a meta object that contains non-standard meta-information.
|
62
|
+
# * jsonapi: an object describing the server’s implementation
|
63
|
+
# * links: a links object related to the primary data.
|
64
|
+
def collection
|
65
|
+
if errors?
|
66
|
+
raise Exception, "IMPLEMENT ERRORS JERK"
|
67
|
+
elsif collection?
|
68
|
+
# Make each item in :data its own document, stick included into that document
|
69
|
+
records = @body[:data].reduce([]) do |agg, resource|
|
70
|
+
json = { data: resource }
|
71
|
+
json[:included] = @body[:included] if @body[:included]
|
72
|
+
agg << json
|
73
|
+
agg
|
74
|
+
end
|
75
|
+
|
76
|
+
Collection.new(records.map{ |datum| Munson.factory(datum) },
|
77
|
+
meta: @body[:meta],
|
78
|
+
jsonapi: @body[:jsonapi],
|
79
|
+
links: @body[:links]
|
80
|
+
)
|
13
81
|
else
|
14
|
-
raise
|
82
|
+
raise Munson::Error, "Called #collection, but response was a single resource. Use ResponseMapper#resource"
|
15
83
|
end
|
16
84
|
end
|
17
85
|
|
18
86
|
def resource
|
19
|
-
if
|
20
|
-
|
87
|
+
if errors?
|
88
|
+
raise Exception, "IMPLEMENT ERRORS JERK"
|
89
|
+
elsif resource?
|
90
|
+
Munson.factory(@body)
|
21
91
|
else
|
22
|
-
raise
|
92
|
+
raise Munson::Error, "Called #resource, but response was a collection of resources. Use ResponseMapper#collection"
|
23
93
|
end
|
24
94
|
end
|
25
95
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
96
|
+
def jsonapi_resources
|
97
|
+
data = collection? ? @body[:data] : [@body[:data]]
|
98
|
+
included = @body[:included] || []
|
99
|
+
(data + included)
|
30
100
|
end
|
31
101
|
|
32
|
-
def
|
33
|
-
@
|
102
|
+
private def errors?
|
103
|
+
@body[:errors].is_a?(Array)
|
34
104
|
end
|
35
105
|
|
36
|
-
def
|
37
|
-
|
38
|
-
@data.map{ |datum| map_resource(datum) }
|
39
|
-
elsif data_is_resource?
|
40
|
-
map_resource(@data)
|
41
|
-
else
|
42
|
-
raise UnsupportedDatatype, "No mapping rule for #{data.class}"
|
43
|
-
end
|
106
|
+
private def resource?
|
107
|
+
@body[:data].is_a?(Hash)
|
44
108
|
end
|
45
109
|
|
46
|
-
def
|
47
|
-
|
48
|
-
klass.new(resource[:attributes].merge(id: resource[:id]))
|
49
|
-
else
|
50
|
-
resource
|
51
|
-
end
|
110
|
+
private def collection?
|
111
|
+
@body[:data].is_a?(Array)
|
52
112
|
end
|
53
113
|
end
|
54
114
|
end
|
data/lib/munson/version.rb
CHANGED