acfs 1.3.3 → 1.6.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/CHANGELOG.md +372 -0
- data/LICENSE +22 -0
- data/README.md +321 -0
- data/acfs.gemspec +38 -0
- data/lib/acfs.rb +51 -0
- data/lib/acfs/adapter/base.rb +26 -0
- data/lib/acfs/adapter/typhoeus.rb +82 -0
- data/lib/acfs/collection.rb +28 -0
- data/lib/acfs/collections/paginatable.rb +76 -0
- data/lib/acfs/configuration.rb +120 -0
- data/lib/acfs/errors.rb +147 -0
- data/lib/acfs/global.rb +101 -0
- data/lib/acfs/location.rb +76 -0
- data/lib/acfs/middleware/base.rb +24 -0
- data/lib/acfs/middleware/json.rb +31 -0
- data/lib/acfs/middleware/logger.rb +23 -0
- data/lib/acfs/middleware/msgpack.rb +32 -0
- data/lib/acfs/middleware/print.rb +23 -0
- data/lib/acfs/middleware/serializer.rb +41 -0
- data/lib/acfs/operation.rb +96 -0
- data/lib/acfs/request.rb +32 -0
- data/lib/acfs/request/callbacks.rb +54 -0
- data/lib/acfs/resource.rb +39 -0
- data/lib/acfs/resource/attributes.rb +270 -0
- data/lib/acfs/resource/attributes/base.rb +29 -0
- data/lib/acfs/resource/attributes/boolean.rb +39 -0
- data/lib/acfs/resource/attributes/date_time.rb +32 -0
- data/lib/acfs/resource/attributes/dict.rb +39 -0
- data/lib/acfs/resource/attributes/float.rb +33 -0
- data/lib/acfs/resource/attributes/integer.rb +29 -0
- data/lib/acfs/resource/attributes/list.rb +36 -0
- data/lib/acfs/resource/attributes/string.rb +26 -0
- data/lib/acfs/resource/attributes/uuid.rb +48 -0
- data/lib/acfs/resource/dirty.rb +37 -0
- data/lib/acfs/resource/initialization.rb +31 -0
- data/lib/acfs/resource/loadable.rb +35 -0
- data/lib/acfs/resource/locatable.rb +135 -0
- data/lib/acfs/resource/operational.rb +26 -0
- data/lib/acfs/resource/persistence.rb +258 -0
- data/lib/acfs/resource/query_methods.rb +266 -0
- data/lib/acfs/resource/service.rb +44 -0
- data/lib/acfs/resource/validation.rb +49 -0
- data/lib/acfs/response.rb +30 -0
- data/lib/acfs/response/formats.rb +27 -0
- data/lib/acfs/response/status.rb +33 -0
- data/lib/acfs/rspec.rb +13 -0
- data/lib/acfs/runner.rb +102 -0
- data/lib/acfs/service.rb +94 -0
- data/lib/acfs/service/middleware.rb +58 -0
- data/lib/acfs/service/middleware/stack.rb +65 -0
- data/lib/acfs/singleton_resource.rb +85 -0
- data/lib/acfs/stub.rb +199 -0
- data/lib/acfs/util.rb +22 -0
- data/lib/acfs/version.rb +16 -0
- data/lib/acfs/yard.rb +6 -0
- data/spec/acfs/adapter/typhoeus_spec.rb +55 -0
- data/spec/acfs/collection_spec.rb +157 -0
- data/spec/acfs/configuration_spec.rb +53 -0
- data/spec/acfs/global_spec.rb +140 -0
- data/spec/acfs/location_spec.rb +25 -0
- data/spec/acfs/middleware/json_spec.rb +79 -0
- data/spec/acfs/middleware/msgpack_spec.rb +62 -0
- data/spec/acfs/operation_spec.rb +12 -0
- data/spec/acfs/request/callbacks_spec.rb +48 -0
- data/spec/acfs/request_spec.rb +79 -0
- data/spec/acfs/resource/attributes/boolean_spec.rb +58 -0
- data/spec/acfs/resource/attributes/date_time_spec.rb +51 -0
- data/spec/acfs/resource/attributes/dict_spec.rb +77 -0
- data/spec/acfs/resource/attributes/float_spec.rb +61 -0
- data/spec/acfs/resource/attributes/integer_spec.rb +36 -0
- data/spec/acfs/resource/attributes/list_spec.rb +60 -0
- data/spec/acfs/resource/attributes/uuid_spec.rb +42 -0
- data/spec/acfs/resource/attributes_spec.rb +179 -0
- data/spec/acfs/resource/dirty_spec.rb +49 -0
- data/spec/acfs/resource/initialization_spec.rb +36 -0
- data/spec/acfs/resource/loadable_spec.rb +22 -0
- data/spec/acfs/resource/locatable_spec.rb +118 -0
- data/spec/acfs/resource/persistance_spec.rb +322 -0
- data/spec/acfs/resource/query_methods_spec.rb +548 -0
- data/spec/acfs/resource/validation_spec.rb +129 -0
- data/spec/acfs/response/formats_spec.rb +52 -0
- data/spec/acfs/response/status_spec.rb +71 -0
- data/spec/acfs/runner_spec.rb +95 -0
- data/spec/acfs/service/middleware_spec.rb +35 -0
- data/spec/acfs/service_spec.rb +48 -0
- data/spec/acfs/singleton_resource_spec.rb +17 -0
- data/spec/acfs/stub_spec.rb +345 -0
- data/spec/acfs_spec.rb +205 -0
- data/spec/fixtures/config.yml +14 -0
- data/spec/spec_helper.rb +42 -0
- data/spec/support/hash.rb +11 -0
- data/spec/support/response.rb +12 -0
- data/spec/support/service.rb +92 -0
- data/spec/support/shared/find_callbacks.rb +50 -0
- metadata +159 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 46dc13b234cd5b704b67a731292b06ad8b32ee3fafb0a7a0af2a1003824e6df8
|
4
|
+
data.tar.gz: a35249f8e2a7a6cc49351b62c75b3fe641b26691132f4fb70b0a183ab041a380
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 07132ad9797084fccd7fdeb31cc9f51572ddda1eb9dc88aaf875cd244000d15823223d3c6c503f0af7ac4cc1f59cb0b748eea75d8592323b807001e82c93d781
|
7
|
+
data.tar.gz: 6d6d15b6841820ae2ee672eec742b417113523ce613f1a7c7d493eeed50232b0915d7edcbf3df1b7060c5ced484bb82f59904e34fe6e17f70babe3b5ddf0a4e7
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,372 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
## Unreleased
|
6
|
+
---
|
7
|
+
|
8
|
+
### New
|
9
|
+
|
10
|
+
### Changes
|
11
|
+
|
12
|
+
### Fixes
|
13
|
+
|
14
|
+
### Breaks
|
15
|
+
|
16
|
+
|
17
|
+
## 1.6.0 - (2021-01-07)
|
18
|
+
---
|
19
|
+
|
20
|
+
### New
|
21
|
+
* Support Ruby 3.0
|
22
|
+
* Use keyword arguments in parameters and when calling methods
|
23
|
+
|
24
|
+
|
25
|
+
## 1.5.1 - (2020-12-30)
|
26
|
+
---
|
27
|
+
|
28
|
+
### Changes
|
29
|
+
* Revert back to using `::MultiJson`
|
30
|
+
|
31
|
+
|
32
|
+
## 1.5.0 - (2020-06-19)
|
33
|
+
---
|
34
|
+
|
35
|
+
### New
|
36
|
+
* Error classes for more HTTP error responses: `400`, `401`, `403`, `500`, `502`, `503`, `504`.
|
37
|
+
|
38
|
+
### Changes
|
39
|
+
* Replace deprecated MultiJson with core JSON module
|
40
|
+
|
41
|
+
|
42
|
+
## 1.4.0 - (2020-06-12)
|
43
|
+
---
|
44
|
+
|
45
|
+
### New
|
46
|
+
* Use strict TCP keepalive probing by default (5s/5s)
|
47
|
+
* Adapter accepts curl request opts
|
48
|
+
|
49
|
+
|
50
|
+
## 1.3.4 - (2020-03-22)
|
51
|
+
---
|
52
|
+
|
53
|
+
### Fixes
|
54
|
+
* Empty package build for Gem release 1.3.3
|
55
|
+
|
56
|
+
|
57
|
+
## 1.3.3 - (2020-03-22)
|
58
|
+
---
|
59
|
+
|
60
|
+
### Changes
|
61
|
+
* Improved handling of low-level connection errors and timeouts
|
62
|
+
|
63
|
+
|
64
|
+
## 1.3.2 - (2019-09-24)
|
65
|
+
|
66
|
+
|
67
|
+
### Fixes
|
68
|
+
* Fix Acfs.on callbacks for empty find_by results (#42)
|
69
|
+
|
70
|
+
|
71
|
+
---
|
72
|
+
|
73
|
+
## 1.3.1 - (2019-07-02)
|
74
|
+
|
75
|
+
### Fixes
|
76
|
+
* Improve URL argument encoding when building resource requests
|
77
|
+
|
78
|
+
## 1.3.0
|
79
|
+
|
80
|
+
* Change default error messages to a more compact representation to ease integration with error reporting services.
|
81
|
+
|
82
|
+
## 1.2.1
|
83
|
+
|
84
|
+
* Fix issues with resources errors if response payload differs from the expected `field => [messages]`, such as `field => message` or `[messages]`.
|
85
|
+
|
86
|
+
## 1.2.0
|
87
|
+
|
88
|
+
* Add Rails 5.2 compatibility
|
89
|
+
|
90
|
+
## 1.1.1
|
91
|
+
|
92
|
+
* `each_item`: Pass collection to provided block (#40)
|
93
|
+
|
94
|
+
## 1.1.0
|
95
|
+
|
96
|
+
* Add support for Rails 5.1
|
97
|
+
|
98
|
+
## 1.0.1
|
99
|
+
|
100
|
+
* Fix deprecation warnings when using ::Mime
|
101
|
+
|
102
|
+
## 1.0.0
|
103
|
+
|
104
|
+
* Switch to first non-development major as it's long time used in production.
|
105
|
+
* Fix NewRelic RPM inference with middleware stack inherited from `ActionDispatch::MiddlewareStack`.
|
106
|
+
|
107
|
+
## 0.48.0
|
108
|
+
|
109
|
+
* Remove #attribute_types broke since f7e4109 (Sep 2013, v0.23)
|
110
|
+
* Fix attribute inheritance on subclassing broken since commit 7cf1d11 (Apr 2014, v0.43)
|
111
|
+
|
112
|
+
## 0.47.0
|
113
|
+
|
114
|
+
* Change blank value handling of dict and list type (0a12ef1)
|
115
|
+
|
116
|
+
## 0.46.0
|
117
|
+
|
118
|
+
* Rework types system (#39)
|
119
|
+
|
120
|
+
## 0.45.0
|
121
|
+
|
122
|
+
* Fetching multiple records (`find(ary)`) is stable now, but untested (#38)
|
123
|
+
* Middleware stack is build on ActionDispatch::MiddlewareStack now
|
124
|
+
* Deprecate legacy middleware names (xyEncoder, xyDecoder)
|
125
|
+
|
126
|
+
## 0.44.0
|
127
|
+
|
128
|
+
* Add option to configure adapter creation and pass option to typhoeus adapter e.g.
|
129
|
+
limiting concurrency.
|
130
|
+
|
131
|
+
## 0.43.2
|
132
|
+
|
133
|
+
* add `total_count` for paginated collections
|
134
|
+
|
135
|
+
## 0.43.1
|
136
|
+
|
137
|
+
* Fix `:with` condition matching on stubs
|
138
|
+
|
139
|
+
## 0.43.0
|
140
|
+
|
141
|
+
* Remove `Acfs::Model` (inherit from `Acfs::Resource`)
|
142
|
+
* Stub does only a partial match of `:with` attributes now
|
143
|
+
* Allow blocks as stub `:return`s
|
144
|
+
|
145
|
+
## 0.42.0
|
146
|
+
|
147
|
+
* Add simple dict attribute type
|
148
|
+
|
149
|
+
## 0.40.0
|
150
|
+
|
151
|
+
* Change `Resource#persisted?` to return true if it is not new
|
152
|
+
|
153
|
+
## 0.39.1
|
154
|
+
|
155
|
+
* Fix automatic path parameter handling for #destroy
|
156
|
+
|
157
|
+
## 0.39.0
|
158
|
+
|
159
|
+
* Add new event acfs.operation.before_process
|
160
|
+
|
161
|
+
## 0.38.0
|
162
|
+
|
163
|
+
* Allow middlewares to abort request processing
|
164
|
+
* Allow middlewares to receive the request operation object (via the request)
|
165
|
+
|
166
|
+
## 0.37.0
|
167
|
+
|
168
|
+
* Add Acfs.on
|
169
|
+
|
170
|
+
## 0.36.0
|
171
|
+
|
172
|
+
* Add #each_page and #each_item query methods
|
173
|
+
|
174
|
+
## 0.35.0
|
175
|
+
|
176
|
+
* Add instrumentation support
|
177
|
+
|
178
|
+
## 0.34.1
|
179
|
+
|
180
|
+
* Fix leaking failed requests in request queues
|
181
|
+
|
182
|
+
## 0.34.0
|
183
|
+
|
184
|
+
* Add support for will_paginate view helper used with `Acfs::Collection`s
|
185
|
+
* Add support for pagination header added by [paginate-responder](https://github.com/jgraichen/paginate-responder)
|
186
|
+
* Improve `Resource#new?` detection by using `loaded?` instead of presence of `:id` attribute
|
187
|
+
|
188
|
+
## 0.33.0
|
189
|
+
|
190
|
+
* Do not raise errors on unknown attributes by default, add :unknown option.
|
191
|
+
* Add support to store unknown attributes
|
192
|
+
|
193
|
+
## 0.32.1
|
194
|
+
|
195
|
+
* Fix multiple callbacks on `QueryMethods#all`
|
196
|
+
|
197
|
+
## 0.32.0
|
198
|
+
|
199
|
+
* Add new attribute type `UUID`
|
200
|
+
|
201
|
+
## 0.31.0
|
202
|
+
|
203
|
+
* Add experimental support for multiple and chained paths with placeholders
|
204
|
+
|
205
|
+
## 0.30.0
|
206
|
+
|
207
|
+
* Add experimental support for multiple operation callbacks (Acfs.add_callback)
|
208
|
+
|
209
|
+
## 0.29.1
|
210
|
+
|
211
|
+
* Fix: rescue NameError and NoMethodError on invalid type
|
212
|
+
|
213
|
+
## 0.29.0
|
214
|
+
|
215
|
+
* Add find_by!
|
216
|
+
|
217
|
+
## 0.28.0
|
218
|
+
|
219
|
+
* Add find_by
|
220
|
+
|
221
|
+
## 0.27.0
|
222
|
+
|
223
|
+
* Reset method to clear stubs, request queues, internal state
|
224
|
+
* Add RSpec helper to enable stubs and clear state after each spec
|
225
|
+
|
226
|
+
## 0.26.0
|
227
|
+
|
228
|
+
* Add support for singleton resources
|
229
|
+
|
230
|
+
## 0.25.0
|
231
|
+
|
232
|
+
* Add option to allow blank attribute values (Johannes Jasper)
|
233
|
+
* Internal changes
|
234
|
+
|
235
|
+
## 0.24.0
|
236
|
+
|
237
|
+
* Fix issues with stubs using type inheritance
|
238
|
+
* Allow '1' as true value for bool attributes (Tino Junge)
|
239
|
+
|
240
|
+
## 0.23.2
|
241
|
+
|
242
|
+
* Fix regression in delegator usage by #find due to resource type inheritance.
|
243
|
+
|
244
|
+
## 0.23.1
|
245
|
+
|
246
|
+
* Fix error class name typo
|
247
|
+
|
248
|
+
## 0.23.0
|
249
|
+
|
250
|
+
* Add Resource Type Inheritance
|
251
|
+
|
252
|
+
## 0.22.2
|
253
|
+
|
254
|
+
* Preserve errors received from service on revalidation (2f1fc178)
|
255
|
+
* Fix parameter ordering bug on stubs (1dc78dc8)
|
256
|
+
|
257
|
+
## 0.22.1
|
258
|
+
|
259
|
+
* Fix hash modification on iteration bug on ActiveModel::Errors due to string keys in error hash
|
260
|
+
|
261
|
+
## 0.22.0
|
262
|
+
|
263
|
+
* Fill local resource errors hash also on 422 responses when saving resources
|
264
|
+
|
265
|
+
## 0.21.1
|
266
|
+
|
267
|
+
* Fix wrong validation context
|
268
|
+
|
269
|
+
## 0.21.0
|
270
|
+
|
271
|
+
* Add update_attributes
|
272
|
+
* Add validation check to `save` method
|
273
|
+
* Inherit attributes to subclasses
|
274
|
+
|
275
|
+
## 0.20.0
|
276
|
+
|
277
|
+
* Remove messaging
|
278
|
+
* Introduce `Acfs::Resource`
|
279
|
+
|
280
|
+
## 0.19.0
|
281
|
+
|
282
|
+
* Add support for DateTime and Float attribute types
|
283
|
+
* Add experimental list attribute type
|
284
|
+
* Allow block usage in stub `with` option
|
285
|
+
* Allow to test if operation stubs were called and how often
|
286
|
+
* Fix bug on operation stubs
|
287
|
+
|
288
|
+
## 0.18.0
|
289
|
+
|
290
|
+
* Basic DELETE operations
|
291
|
+
|
292
|
+
## 0.17.0
|
293
|
+
|
294
|
+
* Basic messaging
|
295
|
+
* Extensible YARD documentation
|
296
|
+
|
297
|
+
## 0.16.0
|
298
|
+
|
299
|
+
* Add YAML configuration
|
300
|
+
* Add external configuration for services
|
301
|
+
* Add Rubinius support
|
302
|
+
|
303
|
+
## 0.15.0
|
304
|
+
|
305
|
+
* Add stubbing capabilities for resources
|
306
|
+
|
307
|
+
## 0.14.0 & 0.13.0
|
308
|
+
|
309
|
+
* Fix response attributes
|
310
|
+
|
311
|
+
## 0.12.0
|
312
|
+
|
313
|
+
* Add JRuby support
|
314
|
+
* Improve handling of error respones (422)
|
315
|
+
|
316
|
+
## 0.11.0
|
317
|
+
|
318
|
+
* Add Logger Middleware
|
319
|
+
* Add handling of error responses
|
320
|
+
|
321
|
+
## 0.10.0
|
322
|
+
|
323
|
+
* Return hash with indifferent access for resource attributes
|
324
|
+
|
325
|
+
## 0.9.0
|
326
|
+
|
327
|
+
* Add create operation
|
328
|
+
|
329
|
+
## 0.8.0
|
330
|
+
|
331
|
+
* Add save operation (PUT and POST)
|
332
|
+
* Add JSON and MessagePack encoder middlewares for encoding request data
|
333
|
+
* ActiveModel::Dirty
|
334
|
+
* Add persistant state methods
|
335
|
+
|
336
|
+
## 0.7.0
|
337
|
+
|
338
|
+
* Per-service middleware stack
|
339
|
+
|
340
|
+
## 0.6.0
|
341
|
+
|
342
|
+
* Add support for multiple ids for .find
|
343
|
+
* Add MessagePack support
|
344
|
+
|
345
|
+
## 0.5.1
|
346
|
+
|
347
|
+
* Fix mime type parsing for mime types with aditional parameters (ActionPack < 4.0)
|
348
|
+
|
349
|
+
## 0.5.0
|
350
|
+
|
351
|
+
* Add mime type support for respones
|
352
|
+
|
353
|
+
## 0.4.0
|
354
|
+
|
355
|
+
* Improve JSON response detection
|
356
|
+
* Add bool attribute type
|
357
|
+
|
358
|
+
## 0.3.0
|
359
|
+
|
360
|
+
* Add tracking for loading state (if resource is loaded or queued)
|
361
|
+
* Add JSON middleware to decode respones
|
362
|
+
* Add middleware support
|
363
|
+
* Add method to fetch single resources or list of resources
|
364
|
+
* Use typhoeus as http library for parallel request processing
|
365
|
+
|
366
|
+
## 0.2.0
|
367
|
+
|
368
|
+
* Allow to define resources and attributes
|
369
|
+
|
370
|
+
## 0.1.0
|
371
|
+
|
372
|
+
* Project start
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Jan Graichen
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,321 @@
|
|
1
|
+
# Acfs - *API client for services*
|
2
|
+
|
3
|
+
[](https://rubygems.org/gems/acfs)
|
4
|
+
[](https://travis-ci.org/jgraichen/acfs)
|
5
|
+
[](https://github.com/jgraichen/acfs/actions?query=branch%3Amaster)
|
6
|
+
[](https://coveralls.io/r/jgraichen/acfs)
|
7
|
+
[](http://rubydoc.info/github/jgraichen/acfs/master/frames)
|
8
|
+
|
9
|
+
Acfs is a library to develop API client libraries for single services within a larger service oriented application.
|
10
|
+
|
11
|
+
Acfs covers model and service abstraction, convenient query and filter methods, full middleware stack for pre-processing requests and responses on a per service level and automatic request queuing and parallel processing. See Usage for more.
|
12
|
+
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Add this line to your application's Gemfile:
|
17
|
+
|
18
|
+
gem 'acfs', '~> 1.3'
|
19
|
+
|
20
|
+
And then execute:
|
21
|
+
|
22
|
+
> bundle
|
23
|
+
|
24
|
+
Or install it yourself as:
|
25
|
+
|
26
|
+
> gem install acfs
|
27
|
+
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
First you need to define your service(s):
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
class UserService < Acfs::Service
|
35
|
+
self.base_url = 'http://users.myapp.org'
|
36
|
+
|
37
|
+
# You can configure middlewares you want to use for the service here.
|
38
|
+
# Each service has it own middleware stack.
|
39
|
+
#
|
40
|
+
use Acfs::Middleware::JsonDecoder
|
41
|
+
use Acfs::Middleware::MessagePackDecoder
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
This specifies where the `UserService` is located. You can now create some models representing resources served by the `UserService`.
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
class User < Acfs::Resource
|
49
|
+
service UserService # Associate `User` model with `UserService`.
|
50
|
+
|
51
|
+
# Define model attributes and types
|
52
|
+
# Types are needed to parse and generate request and response payload.
|
53
|
+
|
54
|
+
attribute :id, :uuid # Types can be classes or symbols.
|
55
|
+
# Symbols will be used to load a class from `Acfs::Model::Attributes` namespace.
|
56
|
+
# Eg. `:uuid` will load class `Acfs::Model::Attributes::Uuid`.
|
57
|
+
|
58
|
+
attribute :name, :string, default: 'Anonymous'
|
59
|
+
attribute :age, ::Acfs::Model::Attributes::Integer # Or use :integer
|
60
|
+
|
61
|
+
end
|
62
|
+
```
|
63
|
+
|
64
|
+
The service and model classes can be shipped as a gem or git submodule to be included by the frontend application(s).
|
65
|
+
|
66
|
+
You can use the model there:
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
@user = User.find 14
|
70
|
+
|
71
|
+
@user.loaded? #=> false
|
72
|
+
|
73
|
+
Acfs.run # This will run all queued request as parallel as possible.
|
74
|
+
# For @user the following URL will be requested:
|
75
|
+
# `http://users.myapp.org/users/14`
|
76
|
+
|
77
|
+
@model.name # => "..."
|
78
|
+
|
79
|
+
@users = User.all
|
80
|
+
@users.loaded? #=> false
|
81
|
+
|
82
|
+
Acfs.run # Will request `http://users.myapp.org/users`
|
83
|
+
|
84
|
+
@users #=> [<User>, ...]
|
85
|
+
```
|
86
|
+
|
87
|
+
If you need multiple resources or dependent resources first define a "plan" how they can be loaded:
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
@user = User.find(5) do |user|
|
91
|
+
# Block will be executed right after user with id 5 is loaded
|
92
|
+
|
93
|
+
# You can load additional resources also from other services
|
94
|
+
# Eg. fetch comments from `CommentSerivce`. The line below will
|
95
|
+
# load comments from `http://comments.myapp.org/comments?user=5`
|
96
|
+
@comments = Comment.where user: user.id
|
97
|
+
|
98
|
+
# You can load multiple resources in parallel if you have multiple
|
99
|
+
# ids.
|
100
|
+
@friends = User.find 1, 4, 10 do |friends|
|
101
|
+
# This block will be executed when all friends are loaded.
|
102
|
+
# [ ... ]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
Acfs.run # This call will fire all request as parallel as possible.
|
107
|
+
# The sequence above would look similar to:
|
108
|
+
#
|
109
|
+
# Start Fin
|
110
|
+
# |===================| `Acfs.run`
|
111
|
+
# |====| /users/5
|
112
|
+
# | |==============| /comments?user=5
|
113
|
+
# | |======| /users/1
|
114
|
+
# | |=======| /users/4
|
115
|
+
# | |======| /users/10
|
116
|
+
|
117
|
+
# Now we can access all resources:
|
118
|
+
|
119
|
+
@user.name # => "John
|
120
|
+
@comments.size # => 25
|
121
|
+
@friends[0].name # => "Miraculix"
|
122
|
+
```
|
123
|
+
|
124
|
+
Use `.find_by` to get first element only. `.find_by` will call the `index`-Action and return the first resource. Optionally passed params will be sent as `GET` parameters and can be used for filtering in the service's controller.
|
125
|
+
```ruby
|
126
|
+
@user = User.find_by age: 24
|
127
|
+
|
128
|
+
Acfs.run # Will request `http://users.myapp.org/users?age=24`
|
129
|
+
|
130
|
+
@user # Contains the first user object returned by the index action
|
131
|
+
```
|
132
|
+
If no object can be found, `.find_by` will return `nil`. The optional callback will then be called with `nil` as parameter. Use `.find_by!` to raise an `Acfs::ResourceNotFound` exception if no object can be found. `.find_by!` will only invoke the optional callback if an object was successfully loaded.
|
133
|
+
|
134
|
+
Acfs has basic update support using `PUT` requests:
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
@user = User.find 5
|
138
|
+
@user.name = "Bob"
|
139
|
+
|
140
|
+
@user.changed? # => true
|
141
|
+
@user.persisted? # => false
|
142
|
+
|
143
|
+
@user.save # Or .save!
|
144
|
+
# Will PUT new resource to service synchronously.
|
145
|
+
|
146
|
+
@user.changed? # => false
|
147
|
+
@user.persisted? # => true
|
148
|
+
```
|
149
|
+
|
150
|
+
|
151
|
+
## Singleton resources
|
152
|
+
|
153
|
+
Singletons can be used in Acfs by creating a new resource which inherits from `SingletonResource`:
|
154
|
+
|
155
|
+
```ruby
|
156
|
+
class Single < Acfs::SingletonResource
|
157
|
+
service UserService # Associate `Single` model with `UserService`.
|
158
|
+
|
159
|
+
# Define model attributes and types as with regular resources
|
160
|
+
|
161
|
+
attribute :name, :string, default: 'Anonymous'
|
162
|
+
attribute :age, :integer
|
163
|
+
|
164
|
+
end
|
165
|
+
```
|
166
|
+
|
167
|
+
The following code explains the routing for singleton resource requests:
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
my_single = Single.new
|
171
|
+
mysingle.save # sends POST request to /single
|
172
|
+
|
173
|
+
my_single = Single.find
|
174
|
+
Acfs.run # sends GET request to /single
|
175
|
+
|
176
|
+
my_single.age = 28
|
177
|
+
my_single.save # sends PUT request to /single
|
178
|
+
|
179
|
+
my_single.delete # sends DELETE request to /single
|
180
|
+
```
|
181
|
+
|
182
|
+
You also can pass parameters to the find call, these will sent as GET params to the index action:
|
183
|
+
|
184
|
+
```ruby
|
185
|
+
my_single = Single.find name: 'Max'
|
186
|
+
Acfs.run # sends GET request with param to /single?name=Max
|
187
|
+
```
|
188
|
+
|
189
|
+
|
190
|
+
## Resource Inheritance
|
191
|
+
|
192
|
+
Acfs provides a resource inheritance similar to ActiveRecord Single Table Inheritance. If a
|
193
|
+
`type` attribute exists and is a valid subclass of your resource they will be converted
|
194
|
+
to you subclassed resources:
|
195
|
+
|
196
|
+
```ruby
|
197
|
+
class Computer < Acfs::Resource
|
198
|
+
...
|
199
|
+
end
|
200
|
+
|
201
|
+
class Pc < Computer end
|
202
|
+
class Mac < Computer end
|
203
|
+
```
|
204
|
+
|
205
|
+
With the following response on `GET /computers` the collection will contain the appropriate
|
206
|
+
subclass resources:
|
207
|
+
|
208
|
+
```json
|
209
|
+
[
|
210
|
+
{ "id": 5, "type": "Computer"},
|
211
|
+
{ "id": 6, "type": "Mac"},
|
212
|
+
{ "id": 8, "type": "Pc"}
|
213
|
+
]
|
214
|
+
```
|
215
|
+
|
216
|
+
```ruby
|
217
|
+
@computers = Computer.all
|
218
|
+
|
219
|
+
Acfs.run
|
220
|
+
|
221
|
+
@computer[0].class # => Computer
|
222
|
+
@computer[1].class # => Mac
|
223
|
+
@computer[2].class # => Pc
|
224
|
+
```
|
225
|
+
|
226
|
+
|
227
|
+
## Stubbing
|
228
|
+
|
229
|
+
You can stub resources in applications using an Acfs service client:
|
230
|
+
|
231
|
+
```ruby
|
232
|
+
# spec_helper.rb
|
233
|
+
|
234
|
+
# This will enable stabs before each spec and clear internal state
|
235
|
+
# after each spec.
|
236
|
+
require 'acfs/rspec'
|
237
|
+
```
|
238
|
+
|
239
|
+
```ruby
|
240
|
+
before do
|
241
|
+
@stub = Acfs::Stub.resource MyUser, :read, with: { id: 1 }, return: { id: 1, name: 'John Smith', age: 32 }
|
242
|
+
Acfs::Stub.resource MyUser, :read, with: { id: 2 }, raise: :not_found
|
243
|
+
Acfs::Stub.resource Session, :create, with: { ident: 'john@exmaple.org', password: 's3cr3t' }, return: { id: 'longhash', user: 1 }
|
244
|
+
Acfs::Stub.resource MyUser, :update, with: lambda { |op| op.data.include? :my_var }, raise: 400
|
245
|
+
end
|
246
|
+
|
247
|
+
it 'should find user number one' do
|
248
|
+
user = MyUser.find 1
|
249
|
+
Acfs.run
|
250
|
+
|
251
|
+
expect(user.id).to be == 1
|
252
|
+
expect(user.name).to be == 'John Smith'
|
253
|
+
expect(user.age).to be == 32
|
254
|
+
|
255
|
+
expect(@stub).to be_called
|
256
|
+
expect(@stub).to_not be_called 5.times
|
257
|
+
end
|
258
|
+
|
259
|
+
it 'should not find user number two' do
|
260
|
+
MyUser.find 3
|
261
|
+
|
262
|
+
expect { Acfs.run }.to raise_error(Acfs::ResourceNotFound)
|
263
|
+
end
|
264
|
+
|
265
|
+
it 'should allow stub resource creation' do
|
266
|
+
session = Session.create! ident: 'john@exmaple.org', password: 's3cr3t'
|
267
|
+
|
268
|
+
expect(session.id).to be == 'longhash'
|
269
|
+
expect(session.user).to be == 1
|
270
|
+
end
|
271
|
+
```
|
272
|
+
|
273
|
+
By default Acfs raises an error when a non stubbed resource should be requested. You can switch of the behavior:
|
274
|
+
|
275
|
+
```ruby
|
276
|
+
before do
|
277
|
+
Acfs::Stub.allow_requests = true
|
278
|
+
end
|
279
|
+
|
280
|
+
it 'should find user number one' do
|
281
|
+
user = MyUser.find 1
|
282
|
+
Acfs.run # Would have raised Acfs::RealRequestNotAllowedError
|
283
|
+
# Will run real request to user service instead.
|
284
|
+
end
|
285
|
+
```
|
286
|
+
|
287
|
+
|
288
|
+
## Instrumentation
|
289
|
+
|
290
|
+
Acfs supports [instrumentation via active support][1].
|
291
|
+
|
292
|
+
Acfs expose to following events
|
293
|
+
|
294
|
+
* `acfs.operation.complete(operation, response)`: Acfs operation completed
|
295
|
+
* `acfs.runner.sync_run(operation)`: Run operation right now skipping queue.
|
296
|
+
* `acfs.runner.enqueue(operation)`: Enqueue operation to be run later.
|
297
|
+
* `acfs.before_run`: directly before `acfs.run`
|
298
|
+
* `acfs.run`: Run all queued operations.
|
299
|
+
|
300
|
+
Read [official guide][2] to see to to subscribe.
|
301
|
+
|
302
|
+
[1]: http://guides.rubyonrails.org/active_support_instrumentation.html
|
303
|
+
[2]: http://guides.rubyonrails.org/active_support_instrumentation.html#subscribing-to-an-event
|
304
|
+
|
305
|
+
|
306
|
+
## Contributing
|
307
|
+
|
308
|
+
1. Fork it
|
309
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
310
|
+
4. Add specs for your feature
|
311
|
+
5. Implement your feature
|
312
|
+
6. Commit your changes (`git commit -am 'Add some feature'`)
|
313
|
+
7. Push to the branch (`git push origin my-new-feature`)
|
314
|
+
8. Create new Pull Request
|
315
|
+
|
316
|
+
|
317
|
+
## License
|
318
|
+
|
319
|
+
MIT License
|
320
|
+
|
321
|
+
Copyright (c) 2013-2020 Jan Graichen. MIT license, see LICENSE for more details.
|