blacksheep 0.2.0 → 0.3.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/Gemfile.lock +2 -2
- data/README.md +15 -15
- data/blacksheep.gemspec +1 -1
- data/lib/blacksheep.rb +3 -0
- data/lib/blacksheep/action.rb +7 -2
- data/lib/blacksheep/action_decorator.rb +20 -0
- data/lib/blacksheep/action_error.rb +16 -0
- data/lib/blacksheep/action_result.rb +27 -0
- data/lib/blacksheep/decorators/default_error_handler.rb +50 -57
- data/lib/blacksheep/decorators/error_handler.rb +2 -2
- data/lib/blacksheep/decorators/json_transformer.rb +6 -5
- data/lib/blacksheep/decorators/localizer.rb +4 -3
- data/lib/blacksheep/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f5e427c080e5f5eaf01f76d9436ff18a36e183318acb2b942105566b34be7c03
|
4
|
+
data.tar.gz: 22221c3900e3dd7d09c796e15e14d765c07cd307add2bbb39696b0767a17f088
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf17a2e2d7732162e0578567d8f04206da221f63d766294670c8b549126e24dd43d5a56451eabb4af6a8a37889ea4aa483a9c77b85c85b38308aec6fe76550c0
|
7
|
+
data.tar.gz: 02cfecdffd2c6d09c3dca2440b6f130e33ae564ab6ba06ba729733f1c2bcc0d9c6605e8db2ef86e307cce4f7bc9250da0f133cb24551b2ad32337ac7d1e23f54
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -24,24 +24,24 @@ Or install it yourself as:
|
|
24
24
|
|
25
25
|
### Actions
|
26
26
|
|
27
|
-
Core
|
27
|
+
Core of blacksheep is the `Blacksheep::Action`. It provides basic functionality to handle rest API actions - but can handle other actions as well. The core methods of actions are:
|
28
28
|
|
29
|
-
* #perform
|
30
|
-
* #call
|
29
|
+
* #perform with a block that implements the action
|
30
|
+
* #call on an action instance for processing and a potential block for result matching (see dcorators below).
|
31
31
|
|
32
32
|
`#perform` takes a block that is executed with the params passed. #perform has the following api:
|
33
33
|
`#perform(params, current_user: (default to nil), **options)`
|
34
34
|
|
35
|
-
`#call` can be used when a Blacksheep::Action is sublassed as an action processing its opertation in a call method with the same signature of `#perform`
|
35
|
+
`#call` can be used when a Blacksheep::Action is sublassed as an action processing its opertation in a call method with the same signature of `#perform`. When using the `ResultMatcher` decorator a block can be used for result matching.
|
36
36
|
|
37
37
|
|
38
38
|
```ruby
|
39
|
-
|
39
|
+
#perform sample
|
40
40
|
action_result = Blacksheep::Action.new.perform(params) do |params|
|
41
41
|
# do somethin with the params that return a `Blacksheep::ActionResult`
|
42
42
|
end
|
43
43
|
|
44
|
-
|
44
|
+
#call sample
|
45
45
|
action_result = MyAction.new.call(params, current_user: current_user)
|
46
46
|
```
|
47
47
|
|
@@ -50,14 +50,14 @@ action_result = MyAction.new.call(params, current_user: current_user)
|
|
50
50
|
|
51
51
|
### Decorators
|
52
52
|
|
53
|
-
This alone does not give any benefit.
|
53
|
+
This alone does not give any benefit. Modifying the action with decorators adds additional functionality:
|
54
54
|
|
55
55
|
* `JsonTransformer`
|
56
56
|
* `Localizer`
|
57
57
|
* `DefaultErrorHandler`
|
58
58
|
* `ResultMatcher`
|
59
59
|
|
60
|
-
The decaorators can be configured
|
60
|
+
The decaorators can be configured globally by defining them in an initializer.
|
61
61
|
|
62
62
|
```ruby
|
63
63
|
# Defining decorator wheras innermost is first
|
@@ -74,7 +74,7 @@ A localizer sets the I18n locale when passed in a request parameter named `_loca
|
|
74
74
|
|
75
75
|
#### Blacksheep::Decorators::DefaultErrorHandler
|
76
76
|
|
77
|
-
A default error handler can be used in API opertions. The handler catches an error and returns
|
77
|
+
A default error handler can be used in API opertions. The handler catches an error and returns an ActionResult such as…
|
78
78
|
|
79
79
|
```ruby
|
80
80
|
def handle_exception(exception)
|
@@ -93,20 +93,20 @@ def handle_exception(exception)
|
|
93
93
|
end
|
94
94
|
```
|
95
95
|
|
96
|
-
You can write your own
|
96
|
+
You can write your own ErrorHandler by including the module `Blacksheep::Decorators::ErrorHandler` and implementing the method `#handle_exception(<Exception>)`.
|
97
97
|
|
98
98
|
|
99
99
|
#### Blacksheep::Decorators::JsonTransformer
|
100
100
|
|
101
|
-
Assuming the params is a json payload with a specific caseing (e.g. camelCase when used in a JS application such as
|
102
|
-
The request has to define the case passed (and hence desired response casing) in the parameter `_case`. If the case is requests as `camel` then
|
101
|
+
Assuming the params is a json payload with a specific caseing (e.g. camelCase when used in a JS application such as Vue) the JsonTransfomer takes the params and transforms it's keys into snake_case as used in ruby often.
|
102
|
+
The request has to define the case passed (and hence desired response casing) in the parameter `_case`. If the case is requests as `camel` then parameter keys are transformed to `snake_case` before beeing passed into the action and are transformed back into CamelCase when leaving the operation.
|
103
103
|
|
104
104
|
If JsonTransfomer is used the action should return a simple JSON structure which is transfformed and stored in an ActionResult.
|
105
105
|
|
106
106
|
|
107
107
|
#### Blacksheep::Decorators::ResultMatcher
|
108
108
|
|
109
|
-
This decorator can be used when implementing your own actions by subclassing `Blacksheep::Action` and using the `#call` style for processing. Adding the
|
109
|
+
This decorator can be used when implementing your own actions by subclassing `Blacksheep::Action` and using the `#call` style for processing. Adding the `ResultMatcher` decorator enables to write a matcher block such as…
|
110
110
|
|
111
111
|
```ruby
|
112
112
|
MyAction.new.call(params) do |m|
|
@@ -122,7 +122,7 @@ MyAction.new.call(params) do |m|
|
|
122
122
|
end
|
123
123
|
```
|
124
124
|
|
125
|
-
The action has to return a Blacksheep::ActionResult which is
|
125
|
+
The action has to return a Blacksheep::ActionResult which is checked for status `:ok` for success case and any other status in failure case.
|
126
126
|
|
127
127
|
|
128
128
|
## Development
|
@@ -134,7 +134,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
134
134
|
```
|
135
135
|
gem build blacksheep
|
136
136
|
gem push blacksheep-0.x.y.gem
|
137
|
-
|
137
|
+
``
|
138
138
|
|
139
139
|
## Contributing
|
140
140
|
|
data/blacksheep.gemspec
CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
|
|
18
18
|
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
19
19
|
if spec.respond_to?(:metadata)
|
20
20
|
spec.metadata["homepage_uri"] = spec.homepage
|
21
|
-
|
21
|
+
spec.metadata["source_code_uri"] = "https://github.com/verticonaut/blacksheep"
|
22
22
|
# spec.metadata["changelog_uri"] = "Put your gem's CHANGELOG.md URL here."
|
23
23
|
else
|
24
24
|
raise "RubyGems 2.0 or newer is required to protect against " \
|
data/lib/blacksheep.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
require "blacksheep/version"
|
2
2
|
require "blacksheep/action_result"
|
3
|
+
require "blacksheep/action_error"
|
3
4
|
require "blacksheep/action_decorator"
|
5
|
+
require "blacksheep/decorators/error_handler"
|
4
6
|
require "blacksheep/decorators/default_error_handler"
|
5
7
|
require "blacksheep/decorators/json_transformer"
|
6
8
|
require "blacksheep/decorators/result_matcher"
|
9
|
+
require "blacksheep/decorators/localizer"
|
7
10
|
require "blacksheep/action"
|
8
11
|
require "blacksheep/version"
|
9
12
|
|
data/lib/blacksheep/action.rb
CHANGED
@@ -28,11 +28,16 @@ module Blacksheep
|
|
28
28
|
@@decorators ||= []
|
29
29
|
end
|
30
30
|
|
31
|
+
#
|
32
|
+
# Adds a decorator to the list of decorated to be applied on Balcksheep::Actions
|
33
|
+
# @param decorator [type] [description]
|
34
|
+
#
|
35
|
+
# @return [type] [description]
|
31
36
|
def add_decorator(decorator)
|
32
|
-
decorators << decorator
|
37
|
+
decorators << decorator unless decorators.include?(decorator)
|
33
38
|
end
|
34
39
|
|
35
|
-
def new(*)
|
40
|
+
def new(*arguments, &block)
|
36
41
|
instance = super
|
37
42
|
|
38
43
|
decorators.each do |decorator|
|
@@ -1,9 +1,29 @@
|
|
1
1
|
require 'delegate'
|
2
2
|
|
3
3
|
module Blacksheep
|
4
|
+
# @class Blacksheep::ActionDecorator
|
4
5
|
class ActionDecorator < SimpleDelegator
|
6
|
+
|
7
|
+
# Access to the decorators class - since original class is overwritten to return the model class.
|
8
|
+
#
|
9
|
+
# @return [Class] The class of the deocrator.
|
10
|
+
# @see [#class]
|
11
|
+
alias_method :__class__, :class
|
12
|
+
|
5
13
|
def class
|
6
14
|
__getobj__.class
|
7
15
|
end
|
16
|
+
|
17
|
+
#
|
18
|
+
# Just for curiosity - get the decorators chain
|
19
|
+
#
|
20
|
+
# @return [type] [description]
|
21
|
+
def decorators_chain
|
22
|
+
decorated = __getobj__
|
23
|
+
chain = decorated.kind_of?(Blacksheep::ActionDecorator) ? decorated.decorators_chain : [ decorated.class ]
|
24
|
+
|
25
|
+
chain.unshift(self.__class__)
|
26
|
+
end
|
27
|
+
|
8
28
|
end
|
9
29
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Blacksheep
|
2
|
+
#
|
3
|
+
# @class Blacksheep::ActionError
|
4
|
+
class ActionError < StandardError
|
5
|
+
attr_reader :identifier, :title
|
6
|
+
|
7
|
+
def initialize(message, title: 'Error', identifier: 'undefined', status: :internal_server_error)
|
8
|
+
@identifier = identifier
|
9
|
+
@title = title
|
10
|
+
@status = status
|
11
|
+
|
12
|
+
super(message)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -8,6 +8,33 @@ module Blacksheep
|
|
8
8
|
@status = status
|
9
9
|
end
|
10
10
|
|
11
|
+
class << self
|
12
|
+
def success(message)
|
13
|
+
json = {
|
14
|
+
_meta: {
|
15
|
+
message: message
|
16
|
+
}
|
17
|
+
}
|
18
|
+
|
19
|
+
new(json, :ok)
|
20
|
+
end
|
21
|
+
|
22
|
+
def error(title: 'Error', message:, status: :internal_server_error, pointer: 'unspecified')
|
23
|
+
json = {
|
24
|
+
errors: [
|
25
|
+
pointer: {
|
26
|
+
source: pointer
|
27
|
+
},
|
28
|
+
title: title,
|
29
|
+
detail: message,
|
30
|
+
]
|
31
|
+
}
|
32
|
+
status = :internal_server_error
|
33
|
+
|
34
|
+
new(json, status)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
11
38
|
def set_data(value)
|
12
39
|
@data = value
|
13
40
|
|
@@ -7,64 +7,57 @@ module Blacksheep
|
|
7
7
|
def handle(exception)
|
8
8
|
json = status = nil
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
# status = :unprocessable_entity # 422
|
23
|
-
# when Pundit::NotAuthorizedError
|
24
|
-
# json = {
|
25
|
-
# errors: [
|
26
|
-
# pointer: {
|
27
|
-
# source: not_authorized_pointer(exception)
|
28
|
-
# },
|
29
|
-
# title: "#{exception.class}",
|
30
|
-
# detail: "#{exception.message}",
|
31
|
-
# ]
|
32
|
-
# }
|
33
|
-
# status = :unauthorized # 401
|
34
|
-
# when Exceptions::AuthenticationInvalid
|
35
|
-
# json = {
|
36
|
-
# errors: [
|
37
|
-
# pointer: {
|
38
|
-
# source: 'Secured Module'
|
39
|
-
# },
|
40
|
-
# title: "#{exception.class}",
|
41
|
-
# detail: "#{exception.message}",
|
42
|
-
# ]
|
43
|
-
# }
|
44
|
-
# status = :unauthorized # 401
|
45
|
-
# else
|
46
|
-
# json = {
|
47
|
-
# errors: [
|
48
|
-
# pointer: {
|
49
|
-
# source: 'Internal'
|
50
|
-
# },
|
51
|
-
# title: "#{exception.class}",
|
52
|
-
# detail: "#{exception.message}",
|
53
|
-
# ]
|
54
|
-
# }
|
55
|
-
# status = :internal_server_error # 500
|
56
|
-
# end
|
10
|
+
case exception
|
11
|
+
when Blacksheep::ActionError
|
12
|
+
json = {
|
13
|
+
errors: [
|
14
|
+
pointer: {
|
15
|
+
source: exception.backtrace.first,
|
16
|
+
identifier: exception.identifier,
|
17
|
+
},
|
18
|
+
title: exception.title,
|
19
|
+
detail: exception.message,
|
20
|
+
]
|
21
|
+
}
|
57
22
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
23
|
+
status = exception.status
|
24
|
+
|
25
|
+
# when Pundit::NotAuthorizedError
|
26
|
+
# json = {
|
27
|
+
# errors: [
|
28
|
+
# pointer: {
|
29
|
+
# source: not_authorized_pointer(exception)
|
30
|
+
# },
|
31
|
+
# title: "#{exception.class}",
|
32
|
+
# detail: "#{exception.message}",
|
33
|
+
# ]
|
34
|
+
# }
|
35
|
+
# status = :unauthorized # 401
|
36
|
+
# when Exceptions::AuthenticationInvalid
|
37
|
+
# json = {
|
38
|
+
# errors: [
|
39
|
+
# pointer: {
|
40
|
+
# source: 'Secured Module'
|
41
|
+
# },
|
42
|
+
# title: "#{exception.class}",
|
43
|
+
# detail: "#{exception.message}",
|
44
|
+
# ]
|
45
|
+
# }
|
46
|
+
# status = :unauthorized # 401
|
47
|
+
|
48
|
+
else
|
49
|
+
json = {
|
50
|
+
errors: [
|
51
|
+
pointer: {
|
52
|
+
source: 'Internal'
|
53
|
+
},
|
54
|
+
title: "#{exception.class}",
|
55
|
+
detail: "#{exception.message}",
|
56
|
+
]
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
status ||= :internal_server_error
|
68
61
|
|
69
62
|
ActionResult.new(json, status)
|
70
63
|
end
|
@@ -5,10 +5,10 @@ module Blacksheep
|
|
5
5
|
|
6
6
|
attr_reader :case, :params
|
7
7
|
|
8
|
-
def call(params, **options)
|
8
|
+
def call(params, current_user: nil, **options)
|
9
9
|
detect_case(params)
|
10
10
|
|
11
|
-
transformed_params = self.
|
11
|
+
transformed_params = self.transform_params(params)
|
12
12
|
|
13
13
|
json = super(transformed_params, **options)
|
14
14
|
|
@@ -20,9 +20,10 @@ module Blacksheep
|
|
20
20
|
def perform(params, current_user: nil, **options, &block)
|
21
21
|
detect_case(params)
|
22
22
|
|
23
|
-
transformed_params = self.
|
23
|
+
transformed_params = self.transform_params(params)
|
24
|
+
|
25
|
+
json = super(transformed_params, current_user: current_user, **options, &block)
|
24
26
|
|
25
|
-
json = block.call(transformed_params)
|
26
27
|
transformed_json = transform_result(json)
|
27
28
|
|
28
29
|
ActionResult.new(transformed_json, :ok)
|
@@ -34,7 +35,7 @@ module Blacksheep
|
|
34
35
|
#
|
35
36
|
# @return [Array, Hash] The params converted into snake_case
|
36
37
|
# @see #snakecase_keys
|
37
|
-
def
|
38
|
+
def transform_params(params)
|
38
39
|
case @case
|
39
40
|
when 'snake', 'as_is'
|
40
41
|
params
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module Blacksheep
|
2
2
|
module Decorators
|
3
3
|
|
4
|
-
# @class Blacksheep::Decorators::
|
4
|
+
# @class Blacksheep::Decorators::Localizer
|
5
5
|
class Localizer < ActionDecorator
|
6
6
|
|
7
|
-
def call(params, **)
|
7
|
+
def call(params, current_user: nil, **options)
|
8
8
|
if (locale = params[:_locale])
|
9
9
|
I18n.with_locale(locale) do
|
10
10
|
super
|
@@ -14,7 +14,8 @@ module Blacksheep
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
def perform(params, **)
|
17
|
+
def perform(params, current_user: nil, **options)
|
18
|
+
|
18
19
|
if (locale = params[:_locale])
|
19
20
|
I18n.with_locale(locale) do
|
20
21
|
super
|
data/lib/blacksheep/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: blacksheep
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Schweizer
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-06-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dry-matcher
|
@@ -87,6 +87,7 @@ files:
|
|
87
87
|
- lib/blacksheep.rb
|
88
88
|
- lib/blacksheep/action.rb
|
89
89
|
- lib/blacksheep/action_decorator.rb
|
90
|
+
- lib/blacksheep/action_error.rb
|
90
91
|
- lib/blacksheep/action_result.rb
|
91
92
|
- lib/blacksheep/decorators/default_error_handler.rb
|
92
93
|
- lib/blacksheep/decorators/error_handler.rb
|
@@ -99,6 +100,7 @@ licenses:
|
|
99
100
|
- MIT
|
100
101
|
metadata:
|
101
102
|
homepage_uri: http://verticonaut.me
|
103
|
+
source_code_uri: https://github.com/verticonaut/blacksheep
|
102
104
|
post_install_message:
|
103
105
|
rdoc_options: []
|
104
106
|
require_paths:
|