api-resource 0.4.1 → 0.4.2
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/lib/api-resource/resource.rb +67 -18
- data/lib/api-resource/version.rb +1 -1
- data/spec/resource_spec.rb +50 -8
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5399345c2d2f04410d0c5d101a341c6118c4f2f3
|
4
|
+
data.tar.gz: b856b7ed659a37531a2c647f6f39d482e73c303e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 25e9c12ee00a9cb4094dd3b4bd1db79269b21ed9906e0a1f1a55f27fc0a3ec62034dff2db46256f9fe1430cadaeea85640cdc760e6e5ae784cc72f7e6e727ca5
|
7
|
+
data.tar.gz: 40d994e49684c47d585120f109931cb4416caec48ca156f668768ce9ac6667d1d7346df940ca6d311c9a7e4ced0930689863ab1b7f5caad90690d29c3bc86f5b
|
@@ -7,6 +7,10 @@ require 'active_support/core_ext/hash/indifferent_access'
|
|
7
7
|
require 'active_support/core_ext/object/to_param'
|
8
8
|
|
9
9
|
module ApiResource
|
10
|
+
|
11
|
+
class ResourceError < StandardError
|
12
|
+
end
|
13
|
+
|
10
14
|
class Resource
|
11
15
|
include ActiveModel::Model
|
12
16
|
include ActiveModel::Serializers::JSON
|
@@ -28,18 +32,30 @@ module ApiResource
|
|
28
32
|
self.attributes = hash if hash
|
29
33
|
end
|
30
34
|
|
35
|
+
def self.resource_path
|
36
|
+
@resource_path || resource_name
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.resource_path=(path)
|
40
|
+
@resource_path = path
|
41
|
+
end
|
42
|
+
|
31
43
|
def self.resource_name
|
32
|
-
|
44
|
+
name.to_s.tableize
|
45
|
+
end
|
46
|
+
|
47
|
+
[:resource_name, :resource_path].each do |name|
|
48
|
+
define_method(name) { self.class.public_send(name) }
|
33
49
|
end
|
34
50
|
|
35
51
|
def self.find(id)
|
36
|
-
result = client(:get, {},
|
52
|
+
result = client(:get, {}, resource_path, id)
|
37
53
|
json = JSON.parse(result)
|
38
54
|
self.new(json['data'] || json)
|
39
55
|
end
|
40
56
|
|
41
57
|
def self.all
|
42
|
-
result = client(:get, {},
|
58
|
+
result = client(:get, {}, resource_path)
|
43
59
|
create_resource_collection(result)
|
44
60
|
end
|
45
61
|
|
@@ -59,23 +75,31 @@ module ApiResource
|
|
59
75
|
end
|
60
76
|
|
61
77
|
def self.where(options, verb=:get)
|
62
|
-
result = client(verb, options,
|
78
|
+
result = client(verb, options, resource_path)
|
63
79
|
create_resource_collection(result)
|
64
80
|
end
|
65
81
|
|
66
82
|
def save!
|
67
|
-
|
68
|
-
|
83
|
+
submit_resource(resource_path, true)
|
84
|
+
self
|
85
|
+
end
|
86
|
+
|
87
|
+
def submit!(options={})
|
88
|
+
path = options.fetch(:path, resource_path)
|
89
|
+
type = options[:type]
|
90
|
+
json = submit_resource(path, false)
|
91
|
+
meta = json['meta']
|
92
|
+
type ||= meta && meta['type']
|
93
|
+
if type
|
94
|
+
returned_type = self.class.load_class(type)
|
95
|
+
returned_type.new(json['data'] || json)
|
69
96
|
else
|
70
|
-
|
71
|
-
json = JSON.parse(result)
|
72
|
-
self.attributes = json['data'] || json
|
97
|
+
self
|
73
98
|
end
|
74
|
-
self
|
75
99
|
end
|
76
100
|
|
77
101
|
def destroy!
|
78
|
-
self.class.client(:delete, id,
|
102
|
+
self.class.client(:delete, id, resource_path) if self.id
|
79
103
|
self
|
80
104
|
end
|
81
105
|
|
@@ -85,18 +109,43 @@ module ApiResource
|
|
85
109
|
|
86
110
|
protected
|
87
111
|
|
112
|
+
def submit_resource(path, save_attributes=false)
|
113
|
+
raise ResourceError unless valid?
|
114
|
+
verb = respond_to?(:id) && id ? :put : :post
|
115
|
+
begin
|
116
|
+
result = self.class.client(verb, attributes, path)
|
117
|
+
rescue RestClient::ExceptionWithResponse => e
|
118
|
+
result = e.http_body
|
119
|
+
raise ResourceError, 'Error executing request'
|
120
|
+
ensure
|
121
|
+
json = parse_and_check_error(result)
|
122
|
+
self.attributes = json['data'] || json if verb == :post && save_attributes
|
123
|
+
end
|
124
|
+
json
|
125
|
+
end
|
126
|
+
|
127
|
+
def parse_and_check_error(result)
|
128
|
+
return nil if result.blank?
|
129
|
+
json = JSON.parse(result)
|
130
|
+
errors_hash = json['errors']
|
131
|
+
if errors_hash.is_a?(Hash)
|
132
|
+
errors_hash.each { |attr, ary| ary.each { |error| errors.add(attr, error) } }
|
133
|
+
nil
|
134
|
+
else
|
135
|
+
json
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
88
139
|
def attributes=(hash)
|
89
140
|
hash.each do |key, value|
|
90
141
|
if respond_to? "#{key}="
|
91
142
|
send("#{key}=", value)
|
92
143
|
else
|
93
|
-
#
|
144
|
+
# define method for associated embedded resource(s)
|
94
145
|
if value.is_a?(Hash)
|
95
|
-
meta = value['meta']
|
96
|
-
data = value['data'] || value
|
146
|
+
meta, data = value['meta'], value['data'] || value
|
97
147
|
elsif value.is_a?(Array)
|
98
|
-
meta = nil
|
99
|
-
data = value
|
148
|
+
meta, data = nil, value
|
100
149
|
else
|
101
150
|
next
|
102
151
|
end
|
@@ -124,7 +173,7 @@ module ApiResource
|
|
124
173
|
end
|
125
174
|
|
126
175
|
def self.with_parent_resource(parent_resource_id, parent_resource_name)
|
127
|
-
result = client(:get, {}, parent_resource_name.pluralize, parent_resource_id,
|
176
|
+
result = client(:get, {}, parent_resource_name.pluralize, parent_resource_id, resource_path)
|
128
177
|
create_resource_collection(result)
|
129
178
|
end
|
130
179
|
|
@@ -139,7 +188,7 @@ module ApiResource
|
|
139
188
|
end
|
140
189
|
|
141
190
|
def self.client(verb, params, *paths)
|
142
|
-
raise
|
191
|
+
raise RuntimeError, 'Empty base_url' if base_url.blank?
|
143
192
|
url = base_url
|
144
193
|
url += '/' unless url.end_with?('/')
|
145
194
|
url += paths.join('/')
|
data/lib/api-resource/version.rb
CHANGED
data/spec/resource_spec.rb
CHANGED
@@ -30,7 +30,7 @@ RSpec.describe ApiResource::Resource do
|
|
30
30
|
def req(verb, path, resource, status=200)
|
31
31
|
stub_request(verb, "#{BlogResource.base_url}#{path}").
|
32
32
|
with(headers: { 'Accept' => 'application/json' }).
|
33
|
-
to_return(status: status, body: resource
|
33
|
+
to_return(status: status, body: resource.is_a?(String) || resource.blank? ? resource : resource.to_json)
|
34
34
|
end
|
35
35
|
|
36
36
|
before do
|
@@ -191,7 +191,7 @@ RSpec.describe ApiResource::Resource do
|
|
191
191
|
expect(blog.id).to be_nil
|
192
192
|
expected_value = { data: { id: 325, title: 'hello' } }
|
193
193
|
|
194
|
-
stub
|
194
|
+
stub = req(:post, '/blogs', expected_value, 201)
|
195
195
|
returned = blog.save!
|
196
196
|
expect(returned).to eq(blog)
|
197
197
|
check_returned_object(Blog, expected_value, blog)
|
@@ -199,9 +199,9 @@ RSpec.describe ApiResource::Resource do
|
|
199
199
|
end
|
200
200
|
it 'PUTs data when id is not nil' do
|
201
201
|
blog_id = 525
|
202
|
-
blog
|
202
|
+
blog = Blog.new(id: blog_id, title: 'hello')
|
203
203
|
|
204
|
-
stub
|
204
|
+
stub = req(:put, '/blogs', nil, 204)
|
205
205
|
returned = blog.save!
|
206
206
|
expect(returned).to eq(blog)
|
207
207
|
expect(blog.id).to eq(blog_id)
|
@@ -211,18 +211,60 @@ RSpec.describe ApiResource::Resource do
|
|
211
211
|
|
212
212
|
context '#destroy!' do
|
213
213
|
it 'DELETEs data when id is not nil' do
|
214
|
-
blog
|
215
|
-
stub
|
214
|
+
blog = Blog.new(id: 323, title: 'hello')
|
215
|
+
stub = req(:delete, '/blogs', '', 204)
|
216
216
|
returned = blog.destroy!
|
217
217
|
expect(returned).to eq(blog)
|
218
218
|
expect(stub).to have_been_requested
|
219
219
|
end
|
220
220
|
it 'not DELETE data when id is nil' do
|
221
|
-
blog
|
222
|
-
stub
|
221
|
+
blog = Blog.new(id: nil, title: 'hello')
|
222
|
+
stub = req(:delete, '/blogs', '', 204)
|
223
223
|
returned = blog.destroy!
|
224
224
|
expect(returned).to eq(blog)
|
225
225
|
expect(stub).to_not have_been_requested
|
226
226
|
end
|
227
227
|
end
|
228
|
+
|
229
|
+
context '#submit!' do
|
230
|
+
|
231
|
+
class SignUp < BlogResource
|
232
|
+
self.resource_path = 'sign_up'
|
233
|
+
attr_accessor :email, :password, :password_confirmation, :name
|
234
|
+
validates :name, presence: true
|
235
|
+
end
|
236
|
+
|
237
|
+
class User < BlogResource
|
238
|
+
attr_accessor :id, :email, :name
|
239
|
+
end
|
240
|
+
|
241
|
+
let (:sign_up) { SignUp.new(email: 'user@example.com', password: 'pass', password_confirmation: 'pass', name: 'Joe') }
|
242
|
+
|
243
|
+
before do
|
244
|
+
|
245
|
+
end
|
246
|
+
it 'uses the resource_path and uses the type in meta' do
|
247
|
+
expected_value = { data: { id: 3, email: 'user@example.com', name: 'Jane' }, meta: { type: 'user' } }
|
248
|
+
stub = req(:post, '/sign_up', expected_value, 200)
|
249
|
+
returned = sign_up.submit!
|
250
|
+
check_returned_object(User, expected_value, returned)
|
251
|
+
expect(stub).to have_been_requested
|
252
|
+
end
|
253
|
+
|
254
|
+
it 'sets the returned errors' do
|
255
|
+
expected_value = { errors: { password_confrimation: ["can't be blank"], email: ["can't be blank", 'is invalid'] } }
|
256
|
+
stub = req(:post, '/sign_up', expected_value, 422)
|
257
|
+
expect(proc { sign_up.submit! }).to raise_error(ApiResource::ResourceError)
|
258
|
+
expect(sign_up.errors.messages).to match(expected_value[:errors])
|
259
|
+
expect(stub).to have_been_requested
|
260
|
+
end
|
261
|
+
|
262
|
+
it 'no request if not valid' do
|
263
|
+
sign_up.name = nil
|
264
|
+
stub = req(:post, '/sign_up', nil, 422)
|
265
|
+
expect(proc { sign_up.submit! }).to raise_error(ApiResource::ResourceError)
|
266
|
+
expect(sign_up.errors[:name]).to be_truthy
|
267
|
+
expect(stub).to_not have_been_requested
|
268
|
+
end
|
269
|
+
end
|
228
270
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: api-resource
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chaker Nakhli
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-03-
|
11
|
+
date: 2015-03-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: simple-hmac
|