salestation 3.5.1 → 3.9.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: a23825882ed43419fc0dd8a70d9cc4cf0b24b318
4
- data.tar.gz: dfbe08b1eaa5bfd9097e4ba9adbe68dead5660ee
2
+ SHA256:
3
+ metadata.gz: c185cbbf51aa9e484fad4fc0099a9b518d11954f5c5c2f11d03f9d086fdeee08
4
+ data.tar.gz: a8c356c5559e1ee1f02da859513badc848003d35cea3167ae66488c631309fca
5
5
  SHA512:
6
- metadata.gz: 1d177e56a051fed32219225b9a7c4a8ad289eeb87c96d4a03a1826df7e198352913850bb6754818a6be912a90777cd4569733710b9c6d921a1fcd31c0dc33a53
7
- data.tar.gz: fb1bfd02506a1d750f62e0ba045cbb1a12f0f6f0fd17a2d6065e4f973e2f0ad1191927626ccbbeb5184f5894ca960aece316df048041cae28bd797cd9cf9cdd2
6
+ metadata.gz: c028e25b401034206c66be282335e78e903edac248adaabecd0041bd5a187397f7bda59d894ed35ded3132aed762e3c8596d4aeeee92f6c5b93fbb9549245ec6
7
+ data.tar.gz: 4dc319fd28ae97aff269c0a6594a2cb271721da31c2ae48d7afd8927ccc352df1526fcfc486146ef55571788bca954de5649ce36a53b73c09767fb28eae99fb1
@@ -1,6 +1,4 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.4
5
- - 2.5
6
- before_install: gem install bundler -v 1.17.3
4
+ - 2.7
data/README.md CHANGED
@@ -75,6 +75,28 @@ Salestation allows and recommends you to define your own custom errors. This is
75
75
  })
76
76
  ```
77
77
 
78
+ ### Providing custom error fields
79
+
80
+ If you need to specify additional error fields you can use `from` method.
81
+ `from` accepts base error on which the rest of the response is built.
82
+ Base error must be a hash or implement `to_h` method.
83
+
84
+ Example:
85
+
86
+ ```
87
+ App::Errors::Conflict.from({details: 'details'}, message: 'message', debug_message: 'debug_message')
88
+ ```
89
+
90
+ Response:
91
+
92
+ ```javascript
93
+ {
94
+ "details": "details",
95
+ "message": "message",
96
+ "debug_message": "debug_message"
97
+ }
98
+ ```
99
+
78
100
  ### Using Extractors
79
101
 
80
102
  Salestation provides extractors to fetch parameters from the request and pass them to the chain.
@@ -142,14 +164,14 @@ end
142
164
 
143
165
  Salestation provides a StatsD middleware which can be used record request
144
166
  execution time. A `timing` call with elapsed seconds is made to the provided
145
- StatsD instance with `path`, `method`, `status` tags.
167
+ StatsD instance with `path`, `method`, `status` and `status_class` tags.
146
168
 
147
169
  ```ruby
148
170
  class Webapp < Sinatra::Base
149
171
  # ...
150
172
  use Salestation::Web::StatsdMiddleware,
151
173
  Statsd.new(host, port),
152
- metric: 'my-metric'
174
+ metric: 'my_service.response.time'
153
175
  end
154
176
  ```
155
177
 
@@ -157,7 +179,7 @@ You can configure per-request tags by defining `salestation.statsd.tags` in sina
157
179
 
158
180
  ```ruby
159
181
  def my_handler(env)
160
- env['salestation.statsd.tags'] = ['foo', 'bar']
182
+ env['salestation.statsd.tags'] = ['foo:bar']
161
183
  # ...
162
184
  end
163
185
  ```
@@ -7,7 +7,7 @@ require 'dry-types'
7
7
  module Salestation
8
8
  class App
9
9
  module Types
10
- include Dry::Types.module
10
+ include Dry::Types()
11
11
  end
12
12
 
13
13
  def initialize(env:, hooks: {})
@@ -3,43 +3,51 @@
3
3
  module Salestation
4
4
  class App
5
5
  module Errors
6
- class InvalidInput < Dry::Struct
6
+ class Error < Dry::Struct
7
+ attribute? :base_error, Types::Coercible::Hash
8
+
9
+ def self.from(base_error, overrides = {})
10
+ new(**overrides, base_error: base_error.to_h)
11
+ end
12
+ end
13
+
14
+ class InvalidInput < Error
7
15
  attribute :errors, Types::Strict::Hash
8
- attribute :hints, Types::Coercible::Hash.default({})
16
+ attribute :hints, Types::Coercible::Hash.default({}.freeze)
9
17
  attribute? :debug_message, Types::Strict::String
10
18
  end
11
19
 
12
- class DependencyCurrentlyUnavailable < Dry::Struct
20
+ class DependencyCurrentlyUnavailable < Error
13
21
  attribute :message, Types::Strict::String
14
22
  attribute? :debug_message, Types::Strict::String
15
23
  end
16
24
 
17
- class RequestedResourceNotFound < Dry::Struct
25
+ class RequestedResourceNotFound < Error
18
26
  attribute :message, Types::Strict::String
19
27
  attribute? :debug_message, Types::Strict::String
20
28
  end
21
29
 
22
- class Forbidden < Dry::Struct
30
+ class Forbidden < Error
23
31
  attribute :message, Types::Strict::String
24
32
  attribute? :debug_message, Types::Strict::String
25
33
  end
26
34
 
27
- class Conflict < Dry::Struct
35
+ class Conflict < Error
28
36
  attribute :message, Types::Strict::String
29
37
  attribute :debug_message, Types::Strict::String
30
38
  end
31
39
 
32
- class NotAcceptable < Dry::Struct
40
+ class NotAcceptable < Error
33
41
  attribute :message, Types::Strict::String
34
42
  attribute :debug_message, Types::Strict::String
35
43
  end
36
44
 
37
- class UnsupportedMediaType < Dry::Struct
45
+ class UnsupportedMediaType < Error
38
46
  attribute :message, Types::Strict::String
39
47
  attribute :debug_message, Types::Strict::String
40
48
  end
41
49
 
42
- class RequestEntityTooLarge < Dry::Struct
50
+ class RequestEntityTooLarge < Error
43
51
  attribute :message, Types::Strict::String
44
52
  attribute? :debug_message, Types::Strict::String
45
53
  end
@@ -8,7 +8,7 @@ require 'json'
8
8
  module Salestation
9
9
  class Web < Module
10
10
  module Types
11
- include Dry::Types.module
11
+ include Dry::Types()
12
12
  end
13
13
 
14
14
  def initialize(errors: {})
@@ -12,26 +12,27 @@ module Salestation
12
12
  App::Errors::DependencyCurrentlyUnavailable => -> (error) {
13
13
  Responses::ServiceUnavailable.new(
14
14
  message: error.message,
15
- debug_message: "Please try again later"
15
+ debug_message: "Please try again later",
16
+ base_error: error.base_error
16
17
  )
17
18
  },
18
19
  App::Errors::RequestedResourceNotFound => -> (error) {
19
- Responses::NotFound.new(message: error.message, debug_message: error.debug_message)
20
+ Responses::NotFound.new(message: error.message, debug_message: error.debug_message, base_error: error.base_error)
20
21
  },
21
22
  App::Errors::Forbidden => -> (error) {
22
- Responses::Forbidden.new(message: error.message, debug_message: error.debug_message)
23
+ Responses::Forbidden.new(message: error.message, debug_message: error.debug_message, base_error: error.base_error)
23
24
  },
24
25
  App::Errors::Conflict => -> (error) {
25
- Responses::Conflict.new(message: error.message, debug_message: error.debug_message)
26
+ Responses::Conflict.new(message: error.message, debug_message: error.debug_message, base_error: error.base_error)
26
27
  },
27
28
  App::Errors::NotAcceptable => -> (error) {
28
- Responses::NotAcceptable.new(message: error.message, debug_message: error.debug_message)
29
+ Responses::NotAcceptable.new(message: error.message, debug_message: error.debug_message, base_error: error.base_error)
29
30
  },
30
31
  App::Errors::UnsupportedMediaType => -> (error) {
31
- Responses::UnsupportedMediaType.new(message: error.message, debug_message: error.debug_message)
32
+ Responses::UnsupportedMediaType.new(message: error.message, debug_message: error.debug_message, base_error: error.base_error)
32
33
  },
33
34
  App::Errors::RequestEntityTooLarge => -> (error) {
34
- Responses::RequestEntityTooLarge.new(message: error.message, debug_message: error.debug_message)
35
+ Responses::RequestEntityTooLarge.new(message: error.message, debug_message: error.debug_message, base_error: error.base_error)
35
36
  }
36
37
  }.freeze
37
38
 
@@ -32,27 +32,37 @@ module Salestation
32
32
  class Error < Response
33
33
  attribute :status, Types::Strict::Integer
34
34
  attribute :message, Types::Strict::String
35
- attribute :debug_message, Types::String.default('')
36
- attribute :context, Types::Hash.default({})
37
- attribute :headers, Types::Hash.default({})
35
+ attribute :debug_message, Types::Coercible::String.default('')
36
+ attribute :context, Types::Hash.default({}.freeze)
37
+ attribute :headers, Types::Hash.default({}.freeze)
38
+ attribute? :base_error, Types::Coercible::Hash
38
39
 
39
40
  def body
40
- {message: message, debug_message: debug_message}
41
+ # Merge into `base_error` to ensure standard fields are not overriden
42
+ (base_error || {}).merge(message: message, debug_message: debug_message)
43
+ end
44
+ end
45
+
46
+ class UnprocessableEntityError < Error
47
+ attribute :form_errors, Types::Hash.default({}.freeze)
48
+
49
+ def body
50
+ super.merge(form_errors: form_errors)
41
51
  end
42
52
  end
43
53
 
44
54
  class Success < Response
45
55
  attribute :status, Types::Strict::Integer
46
56
  attribute :body, Types::Strict::Hash | Types::Strict::Array
47
- attribute :headers, Types::Hash.default({})
57
+ attribute :headers, Types::Hash.default({}.freeze)
48
58
  end
49
59
 
50
60
  class UnprocessableEntityFromSchemaErrors
51
- def self.create(errors:, hints:)
61
+ def self.create(errors:, hints:, base_error: nil)
52
62
  message = parse_errors(errors)
53
63
  debug_message = parse_hints(hints)
54
64
 
55
- UnprocessableEntity.new(message: message, debug_message: debug_message)
65
+ UnprocessableEntity.new(message: message, debug_message: debug_message, form_errors: errors, base_error: base_error)
56
66
  end
57
67
 
58
68
  def self.parse_errors(errors)
@@ -99,7 +109,7 @@ module Salestation
99
109
  Conflict = Error.with_code(409)
100
110
  RequestEntityTooLarge = Error.with_code(413)
101
111
  UnsupportedMediaType = Error.with_code(415)
102
- UnprocessableEntity = Error.with_code(422)
112
+ UnprocessableEntity = UnprocessableEntityError.with_code(422)
103
113
 
104
114
  InternalError = Error.with_code(500)
105
115
  ServiceUnavailable = Error.with_code(503)
@@ -27,9 +27,10 @@ module Salestation
27
27
  end
28
28
 
29
29
  tags = [
30
- "path:#{ path }",
31
- "method:#{ method }",
32
- "status:#{ status }"
30
+ "path:#{path}",
31
+ "method:#{method}",
32
+ "status:#{status}",
33
+ "status_class:#{status / 100}xx"
33
34
  ] + env.fetch(EXTRA_TAGS_ENV_KEY, [])
34
35
 
35
36
  @statsd.timing(@metric, duration_ms(from: start), tags: tags)
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "salestation"
7
- spec.version = "3.5.1"
7
+ spec.version = "3.9.0"
8
8
  spec.authors = ["Glia TechMovers"]
9
9
  spec.email = ["techmovers@glia.com"]
10
10
 
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
20
  spec.require_paths = ["lib"]
21
21
 
22
- spec.add_development_dependency "bundler", "~> 1.13"
22
+ spec.add_development_dependency "bundler", "~> 2.0"
23
23
  spec.add_development_dependency "rake", "~> 13.0"
24
24
  spec.add_development_dependency "rspec", "~> 3.0"
25
25
  spec.add_development_dependency "pry", "~> 0.10.4"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: salestation
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.5.1
4
+ version: 3.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Glia TechMovers
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-31 00:00:00.000000000 Z
11
+ date: 2021-01-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.13'
19
+ version: '2.0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.13'
26
+ version: '2.0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -143,7 +143,7 @@ homepage: ''
143
143
  licenses:
144
144
  - MIT
145
145
  metadata: {}
146
- post_install_message:
146
+ post_install_message:
147
147
  rdoc_options: []
148
148
  require_paths:
149
149
  - lib
@@ -158,9 +158,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
158
158
  - !ruby/object:Gem::Version
159
159
  version: '0'
160
160
  requirements: []
161
- rubyforge_project:
162
- rubygems_version: 2.6.14.4
163
- signing_key:
161
+ rubygems_version: 3.0.6
162
+ signing_key:
164
163
  specification_version: 4
165
164
  summary: ''
166
165
  test_files: []