acfs 1.3.1 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +41 -1
  3. data/README.md +10 -25
  4. data/acfs.gemspec +20 -15
  5. data/lib/acfs.rb +2 -0
  6. data/lib/acfs/adapter/base.rb +6 -8
  7. data/lib/acfs/adapter/typhoeus.rb +25 -6
  8. data/lib/acfs/collection.rb +2 -1
  9. data/lib/acfs/collections/paginatable.rb +4 -3
  10. data/lib/acfs/configuration.rb +14 -7
  11. data/lib/acfs/errors.rb +60 -19
  12. data/lib/acfs/global.rb +12 -2
  13. data/lib/acfs/location.rb +9 -5
  14. data/lib/acfs/middleware/base.rb +5 -1
  15. data/lib/acfs/middleware/json.rb +5 -3
  16. data/lib/acfs/middleware/logger.rb +2 -0
  17. data/lib/acfs/middleware/msgpack.rb +2 -0
  18. data/lib/acfs/middleware/print.rb +2 -0
  19. data/lib/acfs/middleware/serializer.rb +2 -0
  20. data/lib/acfs/operation.rb +20 -3
  21. data/lib/acfs/request.rb +5 -1
  22. data/lib/acfs/request/callbacks.rb +5 -1
  23. data/lib/acfs/resource.rb +2 -0
  24. data/lib/acfs/resource/attributes.rb +5 -2
  25. data/lib/acfs/resource/attributes/base.rb +2 -1
  26. data/lib/acfs/resource/attributes/boolean.rb +2 -0
  27. data/lib/acfs/resource/attributes/date_time.rb +2 -1
  28. data/lib/acfs/resource/attributes/dict.rb +2 -0
  29. data/lib/acfs/resource/attributes/float.rb +5 -3
  30. data/lib/acfs/resource/attributes/integer.rb +2 -0
  31. data/lib/acfs/resource/attributes/list.rb +2 -0
  32. data/lib/acfs/resource/attributes/string.rb +2 -0
  33. data/lib/acfs/resource/attributes/uuid.rb +4 -3
  34. data/lib/acfs/resource/dirty.rb +2 -0
  35. data/lib/acfs/resource/initialization.rb +2 -0
  36. data/lib/acfs/resource/loadable.rb +2 -0
  37. data/lib/acfs/resource/locatable.rb +10 -6
  38. data/lib/acfs/resource/operational.rb +2 -1
  39. data/lib/acfs/resource/persistence.rb +7 -6
  40. data/lib/acfs/resource/query_methods.rb +6 -4
  41. data/lib/acfs/resource/service.rb +3 -1
  42. data/lib/acfs/resource/validation.rb +3 -1
  43. data/lib/acfs/response.rb +2 -0
  44. data/lib/acfs/response/formats.rb +2 -0
  45. data/lib/acfs/response/status.rb +3 -1
  46. data/lib/acfs/rspec.rb +2 -0
  47. data/lib/acfs/runner.rb +6 -1
  48. data/lib/acfs/service.rb +24 -13
  49. data/lib/acfs/service/middleware.rb +2 -0
  50. data/lib/acfs/service/middleware/stack.rb +5 -3
  51. data/lib/acfs/singleton_resource.rb +4 -2
  52. data/lib/acfs/stub.rb +32 -11
  53. data/lib/acfs/util.rb +2 -0
  54. data/lib/acfs/version.rb +4 -2
  55. data/lib/acfs/yard.rb +1 -0
  56. data/spec/acfs/adapter/typhoeus_spec.rb +30 -3
  57. data/spec/acfs/collection_spec.rb +7 -5
  58. data/spec/acfs/configuration_spec.rb +2 -0
  59. data/spec/acfs/global_spec.rb +50 -3
  60. data/spec/acfs/location_spec.rb +2 -0
  61. data/spec/acfs/middleware/json_spec.rb +3 -1
  62. data/spec/acfs/middleware/msgpack_spec.rb +2 -0
  63. data/spec/acfs/operation_spec.rb +2 -0
  64. data/spec/acfs/request/callbacks_spec.rb +2 -0
  65. data/spec/acfs/request_spec.rb +3 -1
  66. data/spec/acfs/resource/attributes/boolean_spec.rb +2 -0
  67. data/spec/acfs/resource/attributes/date_time_spec.rb +2 -0
  68. data/spec/acfs/resource/attributes/dict_spec.rb +4 -2
  69. data/spec/acfs/resource/attributes/float_spec.rb +3 -1
  70. data/spec/acfs/resource/attributes/integer_spec.rb +2 -0
  71. data/spec/acfs/resource/attributes/list_spec.rb +5 -3
  72. data/spec/acfs/resource/attributes/uuid_spec.rb +2 -0
  73. data/spec/acfs/resource/attributes_spec.rb +8 -8
  74. data/spec/acfs/resource/dirty_spec.rb +2 -0
  75. data/spec/acfs/resource/initialization_spec.rb +8 -2
  76. data/spec/acfs/resource/loadable_spec.rb +2 -0
  77. data/spec/acfs/resource/locatable_spec.rb +2 -0
  78. data/spec/acfs/resource/persistance_spec.rb +10 -4
  79. data/spec/acfs/resource/query_methods_spec.rb +24 -17
  80. data/spec/acfs/resource/validation_spec.rb +2 -0
  81. data/spec/acfs/response/formats_spec.rb +3 -1
  82. data/spec/acfs/response/status_spec.rb +2 -0
  83. data/spec/acfs/runner_spec.rb +6 -8
  84. data/spec/acfs/service/middleware_spec.rb +2 -0
  85. data/spec/acfs/service_spec.rb +3 -1
  86. data/spec/acfs/singleton_resource_spec.rb +2 -0
  87. data/spec/acfs/stub_spec.rb +2 -0
  88. data/spec/acfs_spec.rb +2 -0
  89. data/spec/spec_helper.rb +3 -1
  90. data/spec/support/hash.rb +2 -0
  91. data/spec/support/response.rb +2 -0
  92. data/spec/support/service.rb +1 -0
  93. data/spec/support/shared/find_callbacks.rb +2 -0
  94. metadata +13 -28
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '099f37ed68e218d04f91c2f9f636e7b177b84feb8b8e0be4c4403da004937760'
4
- data.tar.gz: bfbf0d3dc7f77eb38f16043051350a468baab870b3b002c35bc9f96df492eb07
3
+ metadata.gz: 53acc88297d3217a5d01db2ce713f935835b05438471fd2b69918029b5480954
4
+ data.tar.gz: d61a2f4e5014dab37d4e1a857d548df8dfb42afcaba219005556f203ea68da65
5
5
  SHA512:
6
- metadata.gz: 29c45b69c95afd11cb58af0e02a383a2c1adcfeefb2521a917e1b7f6606a694c66fa0e2d56796e59127d453f4a1f95ab36c6a2e9a384657992b6a821c946c357
7
- data.tar.gz: cba2e6df7a7988d2d06fc8ca303aa63875736c6d0fc6c0013ecbb36038b559bcfc085058c086468389905947aba375d6add11f3e8010ab2cff1b70628edd8770
6
+ metadata.gz: 35f66d3569256b183cb7c78fed7c41f0ce916f41ec081e60696693af8b869d47e797a53474942c4847cefb621e58d3d52ddf629168c63b7b2d558d1db23cf74a
7
+ data.tar.gz: 5e03be0b16cb469061b55a3c4467a4fa71496925caa086ed5d024ed79aaefdcc568afd970d526c284b08b8db06593f51886d8642f035f78f2ed7f89bd1b8f311
@@ -14,9 +14,49 @@
14
14
  ### Breaks
15
15
 
16
16
 
17
- ## 1.3.1 - (2019-07-02)
17
+ ## 1.5.0 - (2020-06-19)
18
+ ---
19
+
20
+ ### New
21
+ * Error classes for more HTTP error responses: `400`, `401`, `403`, `500`, `502`, `503`, `504`.
22
+
23
+ ### Changes
24
+ * Replace deprecated MultiJson with core JSON module
25
+
26
+
27
+ ## 1.4.0 - (2020-06-12)
28
+ ---
29
+
30
+ ### New
31
+ * Use strict TCP keepalive probing by default (5s/5s)
32
+ * Adapter accepts curl request opts
33
+
34
+
35
+ ## 1.3.4 - (2020-03-22)
36
+ ---
37
+
38
+ ### Fixes
39
+ * Empty package build for Gem release 1.3.3
40
+
41
+
42
+ ## 1.3.3 - (2020-03-22)
18
43
  ---
19
44
 
45
+ ### Changes
46
+ * Improved handling of low-level connection errors and timeouts
47
+
48
+
49
+ ## 1.3.2 - (2019-09-24)
50
+
51
+
52
+ ### Fixes
53
+ * Fix Acfs.on callbacks for empty find_by results (#42)
54
+
55
+
56
+ ---
57
+
58
+ ## 1.3.1 - (2019-07-02)
59
+
20
60
  ### Fixes
21
61
  * Improve URL argument encoding when building resource requests
22
62
 
data/README.md CHANGED
@@ -1,16 +1,16 @@
1
1
  # Acfs - *API client for services*
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/acfs.svg)](http://badge.fury.io/rb/acfs)
4
- [![Build Status](http://img.shields.io/travis/jgraichen/acfs/master.svg)](https://travis-ci.org/jgraichen/acfs)
3
+ [![Gem Version](https://img.shields.io/gem/v/acfs?logo=ruby)](https://rubygems.org/gems/acfs)
4
+ [![Build Status](https://img.shields.io/travis/jgraichen/acfs/master?logo=travis)](https://travis-ci.org/jgraichen/acfs)
5
+ [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/jgraichen/acfs/Test/master?logo=github)](https://github.com/jgraichen/acfs/actions?query=branch%3Amaster)
5
6
  [![Coverage Status](http://img.shields.io/coveralls/jgraichen/acfs/master.svg)](https://coveralls.io/r/jgraichen/acfs)
6
- [![Code Climate](http://img.shields.io/codeclimate/github/jgraichen/acfs.svg)](https://codeclimate.com/github/jgraichen/acfs)
7
- [![Dependency Status](http://img.shields.io/gemnasium/jgraichen/acfs.svg)](https://gemnasium.com/jgraichen/acfs)
8
7
  [![RubyDoc Documentation](http://img.shields.io/badge/rubydoc-here-blue.svg)](http://rubydoc.info/github/jgraichen/acfs/master/frames)
9
8
 
10
9
  Acfs is a library to develop API client libraries for single services within a larger service oriented application.
11
10
 
12
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.
13
12
 
13
+
14
14
  ## Installation
15
15
 
16
16
  Add this line to your application's Gemfile:
@@ -25,6 +25,7 @@ Or install it yourself as:
25
25
 
26
26
  > gem install acfs
27
27
 
28
+
28
29
  ## Usage
29
30
 
30
31
  First you need to define your service(s):
@@ -146,6 +147,7 @@ Acfs has basic update support using `PUT` requests:
146
147
  @user.persisted? # => true
147
148
  ```
148
149
 
150
+
149
151
  ## Singleton resources
150
152
 
151
153
  Singletons can be used in Acfs by creating a new resource which inherits from `SingletonResource`:
@@ -184,6 +186,7 @@ my_single = Single.find name: 'Max'
184
186
  Acfs.run # sends GET request with param to /single?name=Max
185
187
  ```
186
188
 
189
+
187
190
  ## Resource Inheritance
188
191
 
189
192
  Acfs provides a resource inheritance similar to ActiveRecord Single Table Inheritance. If a
@@ -220,6 +223,7 @@ Acfs.run
220
223
  @computer[2].class # => Pc
221
224
  ```
222
225
 
226
+
223
227
  ## Stubbing
224
228
 
225
229
  You can stub resources in applications using an Acfs service client:
@@ -280,6 +284,7 @@ it 'should find user number one' do
280
284
  end
281
285
  ```
282
286
 
287
+
283
288
  ## Instrumentation
284
289
 
285
290
  Acfs supports [instrumentation via active support][1].
@@ -297,21 +302,6 @@ Read [official guide][2] to see to to subscribe.
297
302
  [1]: http://guides.rubyonrails.org/active_support_instrumentation.html
298
303
  [2]: http://guides.rubyonrails.org/active_support_instrumentation.html#subscribing-to-an-event
299
304
 
300
- ## Roadmap
301
-
302
- * Update
303
- * Better new? detection eg. storing ETag from request resources.
304
- * Use PATCH for with only changed attributes and `If-Unmodifed-Since`
305
- and `If-Match` header fields if resource was surly loaded from service
306
- and not created with an id (e.g `User.new id: 5, name: "john"`).
307
- * Conflict detection (ETag / If-Unmodified-Since)
308
- * High level features
309
- * Support for custom mime types on client and server side. (`application/vnd.myservice.user.v2+msgpack`)
310
- * Server side components
311
- * Reusing model definitions for generating responses?
312
- * Rails responders providing REST operations with integrated ETag,
313
- Modified Headers, conflict detection, ...
314
- * Documentation
315
305
 
316
306
  ## Contributing
317
307
 
@@ -323,14 +313,9 @@ Read [official guide][2] to see to to subscribe.
323
313
  7. Push to the branch (`git push origin my-new-feature`)
324
314
  8. Create new Pull Request
325
315
 
326
- ## Contributors
327
-
328
- * [Nicolas Fricke](https://github.com/nicolas-fricke)
329
- * [Tino Junge](https://github.com/tino-junge)
330
- * [Malte Swart](https://github.com/mswart)
331
316
 
332
317
  ## License
333
318
 
334
319
  MIT License
335
320
 
336
- Copyright (c) 2013 Jan Graichen. MIT license, see LICENSE for more details.
321
+ Copyright (c) 2013-2020 Jan Graichen. MIT license, see LICENSE for more details.
@@ -1,5 +1,6 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
5
  require 'acfs/version'
5
6
 
@@ -7,31 +8,35 @@ Gem::Specification.new do |spec|
7
8
  spec.name = 'acfs'
8
9
  spec.version = Acfs::VERSION
9
10
  spec.authors = ['Jan Graichen']
10
- spec.email = %w(jg@altimos.de)
11
- spec.description = 'API Client For Services'
12
- spec.summary = 'An abstract API base client for service oriented application.'
11
+ spec.email = %w[jgraichen@altimos.de]
13
12
  spec.homepage = 'https://github.com/jgraichen/acfs'
14
13
  spec.license = 'MIT'
14
+ spec.description = 'API Client For Services'
15
+ spec.summary = <<~SUMMARY.strip
16
+ An abstract API base client for service oriented application.
17
+ SUMMARY
18
+
19
+ spec.files = Dir['**/*'].grep(%r{
20
+ ^((bin|lib|test|spec|features)/|
21
+ .*\.gemspec|.*LICENSE.*|.*README.*|.*CHANGELOG.*)
22
+ }xi)
15
23
 
16
- spec.files = Dir['**/*'].grep(%r{^((bin|lib|test|spec|features)/|.*\.gemspec|.*LICENSE.*|.*README.*|.*CHANGELOG.*)})
17
24
  spec.executables = spec.files.grep(%r{^bin/}) {|f| File.basename(f) }
18
25
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = %w(lib)
20
-
21
- spec.add_runtime_dependency 'activesupport', '>= 4.2'
22
- spec.add_runtime_dependency 'activemodel', '>= 4.2'
23
- spec.add_runtime_dependency 'actionpack', '>= 4.2'
24
- spec.add_runtime_dependency 'multi_json'
25
-
26
- # Bundle update w/o version resolves to 0.3.3 ...
27
- spec.add_runtime_dependency 'typhoeus', '~> 1.0'
26
+ spec.require_paths = %w[lib]
28
27
 
28
+ spec.add_runtime_dependency 'actionpack', '>= 5.2'
29
+ spec.add_runtime_dependency 'activemodel', '>= 5.2'
30
+ spec.add_runtime_dependency 'activesupport', '>= 5.2'
29
31
  spec.add_runtime_dependency 'rack'
32
+ spec.add_runtime_dependency 'typhoeus', '~> 1.0'
30
33
 
31
34
  spec.add_development_dependency 'bundler'
32
35
 
33
36
  if ENV['TRAVIS_BUILD_NUMBER'] && !ENV['TRAVIS_TAG']
34
37
  # Append travis build number for auto-releases
38
+ # rubocop:disable Gemspec/DuplicatedAssignment
35
39
  spec.version = "#{spec.version}.1.b#{ENV['TRAVIS_BUILD_NUMBER']}"
40
+ # rubocop:enable Gemspec/DuplicatedAssignment
36
41
  end
37
42
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support'
2
4
  require 'active_support/core_ext/hash'
3
5
  require 'active_support/core_ext/class'
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Acfs::Adapter
2
4
  # Base adapter handling operation queuing
3
5
  # and processing.
@@ -5,22 +7,18 @@ module Acfs::Adapter
5
7
  class Base
6
8
  # Start processing queued requests.
7
9
  #
8
- def start
9
- end
10
+ def start; end
10
11
 
11
12
  # Abort running and queued requests.
12
13
  #
13
- def abort
14
- end
14
+ def abort; end
15
15
 
16
16
  # Run request right now skipping queue.
17
17
  #
18
- def run(_)
19
- end
18
+ def run(_); end
20
19
 
21
20
  # Enqueue request to be run later.
22
21
  #
23
- def queue(_)
24
- end
22
+ def queue(_); end
25
23
  end
26
24
  end
@@ -1,17 +1,26 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'typhoeus'
2
4
 
3
5
  module Acfs
4
6
  module Adapter
7
+ DEFAULT_OPTIONS = {
8
+ tcp_keepalive: true,
9
+ tcp_keepidle: 5,
10
+ tcp_keepintvl: 5
11
+ }.freeze
12
+
5
13
  # Adapter for Typhoeus.
6
14
  #
7
15
  class Typhoeus < Base
8
- def initialize(**kwargs)
9
- @options = kwargs
16
+ def initialize(opts: {}, **kwargs)
17
+ @opts = DEFAULT_OPTIONS.merge(opts)
18
+ @kwargs = kwargs
10
19
  end
11
20
 
12
21
  def start
13
22
  hydra.run
14
- rescue
23
+ rescue StandardError
15
24
  @hydra = nil
16
25
  raise
17
26
  end
@@ -29,20 +38,30 @@ module Acfs
29
38
  protected
30
39
 
31
40
  def hydra
32
- @hydra ||= ::Typhoeus::Hydra.new(**@options)
41
+ @hydra ||= ::Typhoeus::Hydra.new(**@kwargs)
33
42
  end
34
43
 
35
44
  def convert_request(req)
36
- request = ::Typhoeus::Request.new req.url,
45
+ opts = {
37
46
  method: req.method,
38
47
  params: req.params,
39
48
  headers: req.headers.merge(
40
- 'Expect' => '',
49
+ 'Expect' => '',
41
50
  'Transfer-Encoding' => ''
42
51
  ),
43
52
  body: req.body
53
+ }
54
+
55
+ request = ::Typhoeus::Request.new(req.url, **@opts.merge(opts))
44
56
 
45
57
  request.on_complete do |response|
58
+ raise ::Acfs::TimeoutError.new(req) if response.timed_out?
59
+
60
+ if response.code.zero?
61
+ # Failed to get HTTP response
62
+ raise ::Acfs::RequestError.new(req, response.return_message)
63
+ end
64
+
46
65
  req.complete! convert_response(req, response)
47
66
  end
48
67
 
@@ -1,10 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'delegate'
2
4
 
3
5
  require 'acfs/resource/loadable'
4
6
  require 'acfs/collections/paginatable'
5
7
 
6
8
  module Acfs
7
- #
8
9
  class Collection < ::Delegator
9
10
  include Resource::Loadable
10
11
  include Acfs::Util::Callbacks
@@ -1,5 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Acfs::Collections
2
- #
3
4
  module Paginatable
4
5
  extend ActiveSupport::Concern
5
6
 
@@ -67,8 +68,8 @@ module Acfs::Collections
67
68
  def setup_params(params)
68
69
  @current_page = begin
69
70
  Integer params.fetch(:page, 1)
70
- rescue ArgumentError
71
- params[:page]
71
+ rescue ArgumentError
72
+ params[:page]
72
73
  end
73
74
  end
74
75
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'uri'
2
4
  require 'yaml'
3
5
 
@@ -25,7 +27,7 @@ module Acfs
25
27
  # @return [undefined]
26
28
  #
27
29
  def configure(&block)
28
- if block.arity > 0
30
+ if block.arity.positive?
29
31
  block.call self
30
32
  else
31
33
  instance_eval(&block)
@@ -37,8 +39,12 @@ module Acfs
37
39
  # @overload locate(service, uri)
38
40
  # Configures URL where a service can be reached.
39
41
  #
40
- # @param [Symbol] service Service identity key for service that is reachable under given URL.
41
- # @param [String] uri URL where service is reachable. Will be passed to {URI.parse}.
42
+ # @param [Symbol] service
43
+ # Service identity key for service that is reachable under given URL.
44
+ #
45
+ # @param [String] uri
46
+ # URL where service is reachable. Will be passed to {URI.parse}.
47
+ #
42
48
  # @return [undefined]
43
49
  #
44
50
  # @overload locate(service)
@@ -64,7 +70,7 @@ module Acfs
64
70
  # @return [undefined]
65
71
  #
66
72
  def load(filename)
67
- config = YAML.load File.read filename
73
+ config = YAML.safe_load(File.read(filename), [], [], true)
68
74
  env = ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development'
69
75
 
70
76
  config = config[env] if config.key? env
@@ -95,18 +101,19 @@ module Acfs
95
101
  # @return [Configuration]
96
102
  #
97
103
  def current
98
- @configuration ||= new
104
+ @current ||= new
99
105
  end
100
106
 
101
107
  # @api private
102
108
  #
103
- # Swap configuration object with given new one. Must be a {Configuration} object.
109
+ # Swap configuration object with given new one. Must be
110
+ # a {Configuration} object.
104
111
  #
105
112
  # @param [Configuration] configuration
106
113
  # @return [undefined]
107
114
  #
108
115
  def set(configuration)
109
- @configuration = configuration if configuration.is_a? Configuration
116
+ @current = configuration if configuration.is_a? Configuration
110
117
  end
111
118
  end
112
119
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Acfs
2
4
  # Acfs base error.
3
5
  #
@@ -10,6 +12,24 @@ module Acfs
10
12
 
11
13
  class UnsupportedOperation < StandardError; end
12
14
 
15
+ class RequestError < Error
16
+ attr_reader :request
17
+
18
+ def initialize(request, message)
19
+ @request = request
20
+
21
+ message = "#{message}: #{request.method.upcase} #{request.url}"
22
+
23
+ super message: message
24
+ end
25
+ end
26
+
27
+ class TimeoutError < RequestError
28
+ def initialize(request)
29
+ super(request, 'Timeout reached')
30
+ end
31
+ end
32
+
13
33
  # Response error containing the responsible response object.
14
34
  #
15
35
  class ErroneousResponse < Error
@@ -17,17 +37,15 @@ module Acfs
17
37
 
18
38
  def initialize(opts = {})
19
39
  @response = opts[:response]
20
- message = opts[:message]
21
- if response
22
- if message
23
- message << ':'
24
- else
25
- message = 'Received'
26
- end
27
- message << " #{response.code} for #{response.request.method.upcase} #{response.request.url} #{response.request.format}"
28
- else
29
- message ||= 'Received erroneous response'
30
- end
40
+
41
+ message = if response
42
+ (opts[:message] ? opts[:message] + ':' : 'Received') +
43
+ " #{response.code} for #{response.request.method.upcase}" \
44
+ " #{response.request.url} #{response.request.format}"
45
+ else
46
+ opts[:message] || 'Received erroneous response'
47
+ end
48
+
31
49
  super opts, message
32
50
  end
33
51
  end
@@ -41,17 +59,27 @@ module Acfs
41
59
  @stubs = opts.delete :stubs
42
60
  @operation = opts.delete :operation
43
61
 
44
- super opts, "Ambiguous stubs for #{operation.action} on #{operation.resource}.\n" +
45
- stubs.map {|s| " #{s.opts.pretty_inspect}" }.join
62
+ message = "Ambiguous stubs for #{operation.action} " \
63
+ "on #{operation.resource}.\n" +
64
+ stubs.map {|s| " #{s.opts.pretty_inspect}" }.join
65
+
66
+ super opts, message
46
67
  end
47
68
  end
48
69
 
49
- # Resource not found error raised on a 404 response
50
- #
51
- class ResourceNotFound < ErroneousResponse
52
- end
70
+ # 400
71
+ class BadRequest < ErroneousResponse; end
53
72
 
54
- #
73
+ # 401
74
+ class Unauthorized < ErroneousResponse; end
75
+
76
+ # 403
77
+ class Forbidden < ErroneousResponse; end
78
+
79
+ # 404
80
+ class ResourceNotFound < ErroneousResponse; end
81
+
82
+ # 422
55
83
  class InvalidResource < ErroneousResponse
56
84
  attr_reader :errors, :resource
57
85
 
@@ -71,6 +99,18 @@ module Acfs
71
99
  end
72
100
  end
73
101
 
102
+ # 500
103
+ class ServerError < ErroneousResponse; end
104
+
105
+ # 502
106
+ class BadGateway < ErroneousResponse; end
107
+
108
+ # 503
109
+ class ServiceUnavailable < ErroneousResponse; end
110
+
111
+ # 504
112
+ class GatewayTimeout < ErroneousResponse; end
113
+
74
114
  # A ResourceNotLoaded error will be thrown when calling some
75
115
  # modifing methods on not loaded resources as it is usally
76
116
  # unwanted to call e.g. `update_attributes` on a not loaded
@@ -97,7 +137,8 @@ module Acfs
97
137
  def initialize(opts = {})
98
138
  @base_class = opts.delete :base_class
99
139
  @type_name = opts.delete :type_name
100
- opts[:message] = "Received resource type `#{type_name}` is no subclass of #{base_class}"
140
+ opts[:message] = "Received resource type `#{type_name}` " \
141
+ "is no subclass of #{base_class}"
101
142
  super
102
143
  end
103
144
  end