blacksheep 0.1.0 → 0.2.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/README.md +107 -1
- data/lib/blacksheep.rb +1 -2
- data/lib/blacksheep/action.rb +2 -2
- data/lib/blacksheep/{json_result.rb → action_result.rb} +8 -8
- data/lib/blacksheep/decorators/default_error_handler.rb +2 -14
- data/lib/blacksheep/decorators/error_handler.rb +24 -0
- data/lib/blacksheep/decorators/json_transformer.rb +15 -8
- data/lib/blacksheep/decorators/result_matcher.rb +8 -9
- data/lib/blacksheep/version.rb +1 -1
- metadata +3 -3
- data/lib/blacksheep/json_meta.rb +0 -41
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 75dfef125950bec755e918dba9e56bf6877ab8a3baedc2e42d16b62e31aa395c
|
4
|
+
data.tar.gz: 4ef04a290cd93670d126e910022cada3a16bb446af06eb26e759073c87e2a3b6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '0084555561e9b92801cf7524379c6e3523eda987a612beb869f8be81abf69c4ebba673ebf609c1310074f7f2d65c954998061cb70701e1052a6efb6507431eeb'
|
7
|
+
data.tar.gz: d5e729097addb0df435e051c8289de2e8c0ca06d1d17d1690c630ab251a657d169719b5dc70cde2744537aac5f0cf544d9ee05d2596668151ff306609d5054b2
|
data/README.md
CHANGED
@@ -22,7 +22,108 @@ Or install it yourself as:
|
|
22
22
|
|
23
23
|
## Usage
|
24
24
|
|
25
|
-
|
25
|
+
### Actions
|
26
|
+
|
27
|
+
Core if blacksheep is the Blacksheep::Action. It provides basic fuctionality to handle rest API actions - but can handle other actions as well. The core methods of Actions are:
|
28
|
+
|
29
|
+
* #perform, and…
|
30
|
+
* #call
|
31
|
+
|
32
|
+
`#perform` takes a block that is executed with the params passed. #perform has the following api:
|
33
|
+
`#perform(params, current_user: (default to nil), **options)`
|
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`
|
36
|
+
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
##perform sample
|
40
|
+
action_result = Blacksheep::Action.new.perform(params) do |params|
|
41
|
+
# do somethin with the params that return a `Blacksheep::ActionResult`
|
42
|
+
end
|
43
|
+
|
44
|
+
##perform sample
|
45
|
+
action_result = MyAction.new.call(params, current_user: current_user)
|
46
|
+
```
|
47
|
+
|
48
|
+
`Blacksheeep::ActionResult` has a data and a status attribute. In case of json api actions its expected to store a json response into the data attribute, and the respective http status into the status attribute.
|
49
|
+
|
50
|
+
|
51
|
+
### Decorators
|
52
|
+
|
53
|
+
This alone does not give any benefit. It more interesting to modifiy the action with decorators such as:
|
54
|
+
|
55
|
+
* `JsonTransformer`
|
56
|
+
* `Localizer`
|
57
|
+
* `DefaultErrorHandler`
|
58
|
+
* `ResultMatcher`
|
59
|
+
|
60
|
+
The decaorators can be configured globaly by defining them in an initializer.
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
# Defining decorator wheras innermost is first
|
64
|
+
Blacksheep::Action.add_decorator(Blacksheep::Decorators::Localizer)
|
65
|
+
Blacksheep::Action.add_decorator(Blacksheep::Decorators::DefaultErrorHandler)
|
66
|
+
Blacksheep::Action.add_decorator(Blacksheep::Decorators::JsonTransformer)
|
67
|
+
Blacksheep::Action.add_decorator(Blacksheep::Decorators::ResultMatcher)
|
68
|
+
```
|
69
|
+
|
70
|
+
#### Blacksheep::Decorators::Localizer
|
71
|
+
|
72
|
+
A localizer sets the I18n locale when passed in a request parameter named `_locale`.
|
73
|
+
|
74
|
+
|
75
|
+
#### Blacksheep::Decorators::DefaultErrorHandler
|
76
|
+
|
77
|
+
A default error handler can be used in API opertions. The handler catches an error and returns a JsonResultObject such as
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
def handle_exception(exception)
|
81
|
+
json = {
|
82
|
+
errors: [
|
83
|
+
pointer: {
|
84
|
+
source: 'Internal'
|
85
|
+
},
|
86
|
+
title: "#{exception.class}",
|
87
|
+
detail: "#{exception.message}",
|
88
|
+
]
|
89
|
+
}
|
90
|
+
status = :internal_server_error # 500
|
91
|
+
|
92
|
+
ActionResult.new(json, status)
|
93
|
+
end
|
94
|
+
```
|
95
|
+
|
96
|
+
You can write your own Errorhandler by including the module `Blacksheep::Decorators::ErrorHandler` and implementing the method `#handle(exception)`.
|
97
|
+
|
98
|
+
|
99
|
+
#### Blacksheep::Decorators::JsonTransformer
|
100
|
+
|
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 tranforms 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 paramter keys are tranformed to `snake_case` before going into the action and are transformed back into CamelCase when leaving the operation.
|
103
|
+
|
104
|
+
If JsonTransfomer is used the action should return a simple JSON structure which is transfformed and stored in an ActionResult.
|
105
|
+
|
106
|
+
|
107
|
+
#### Blacksheep::Decorators::ResultMatcher
|
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 matcher decorator enables to write a matchers such as e.g.
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
MyAction.new.call(params) do |m|
|
113
|
+
m.success do |action_result|
|
114
|
+
# do something in success case
|
115
|
+
end
|
116
|
+
m.failure :unauthorized do |action_result|
|
117
|
+
# special handling for unauthorized access
|
118
|
+
end
|
119
|
+
m.failure do |v|
|
120
|
+
# any other failure
|
121
|
+
end
|
122
|
+
end
|
123
|
+
```
|
124
|
+
|
125
|
+
The action has to return a Blacksheep::ActionResult which is check for status :ok in sucess case and any other status in failure case.
|
126
|
+
|
26
127
|
|
27
128
|
## Development
|
28
129
|
|
@@ -30,6 +131,11 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
|
30
131
|
|
31
132
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
32
133
|
|
134
|
+
```
|
135
|
+
gem build blacksheep
|
136
|
+
gem push blacksheep-0.x.y.gem
|
137
|
+
```
|
138
|
+
|
33
139
|
## Contributing
|
34
140
|
|
35
141
|
Bug reports and pull requests are welcome on GitHub at https://github.com/verticonaut/blacksheep.
|
data/lib/blacksheep.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
require "blacksheep/version"
|
2
|
-
require "blacksheep/
|
3
|
-
require "blacksheep/json_result"
|
2
|
+
require "blacksheep/action_result"
|
4
3
|
require "blacksheep/action_decorator"
|
5
4
|
require "blacksheep/decorators/default_error_handler"
|
6
5
|
require "blacksheep/decorators/json_transformer"
|
data/lib/blacksheep/action.rb
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
module Blacksheep
|
2
|
-
class
|
2
|
+
class ActionResult
|
3
3
|
|
4
|
-
attr_reader :
|
4
|
+
attr_reader :data, :status
|
5
5
|
|
6
|
-
def initialize(
|
7
|
-
@
|
6
|
+
def initialize(data, status)
|
7
|
+
@data = data
|
8
8
|
@status = status
|
9
9
|
end
|
10
10
|
|
11
|
-
def
|
12
|
-
@
|
11
|
+
def set_data(value)
|
12
|
+
@data = value
|
13
13
|
|
14
14
|
self
|
15
15
|
end
|
@@ -24,9 +24,9 @@ module Blacksheep
|
|
24
24
|
@status == :ok
|
25
25
|
end
|
26
26
|
|
27
|
-
def
|
27
|
+
def render_json(json_wrap: 'data')
|
28
28
|
{
|
29
|
-
json: wrap(
|
29
|
+
json: wrap(@data, json_wrap: json_wrap),
|
30
30
|
status: status
|
31
31
|
}
|
32
32
|
end
|
@@ -2,19 +2,7 @@ module Blacksheep
|
|
2
2
|
module Decorators
|
3
3
|
# @class Blacksheep::Decorators::DefaultErrorHandler
|
4
4
|
class DefaultErrorHandler < ActionDecorator
|
5
|
-
|
6
|
-
def call(*)
|
7
|
-
puts error_handler: "*" * 50
|
8
|
-
super
|
9
|
-
rescue => exception
|
10
|
-
handle(exception)
|
11
|
-
end
|
12
|
-
|
13
|
-
def perform(*)
|
14
|
-
super
|
15
|
-
rescue => exception
|
16
|
-
handle(exception)
|
17
|
-
end
|
5
|
+
include ErrorHandler
|
18
6
|
|
19
7
|
def handle(exception)
|
20
8
|
json = status = nil
|
@@ -78,7 +66,7 @@ module Blacksheep
|
|
78
66
|
}
|
79
67
|
status = :internal_server_error # 500
|
80
68
|
|
81
|
-
|
69
|
+
ActionResult.new(json, status)
|
82
70
|
end
|
83
71
|
|
84
72
|
# def not_authorized_pointer(exception)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Blacksheep
|
2
|
+
module Decorators
|
3
|
+
# @class Blacksheep::Decorators::ErrorHandler
|
4
|
+
class ErrorHandler
|
5
|
+
|
6
|
+
def call(*)
|
7
|
+
super
|
8
|
+
rescue => exception
|
9
|
+
handle(exception)
|
10
|
+
end
|
11
|
+
|
12
|
+
def perform(*)
|
13
|
+
super
|
14
|
+
rescue => exception
|
15
|
+
handle(exception)
|
16
|
+
end
|
17
|
+
|
18
|
+
def handle(exception)
|
19
|
+
raise Blacksheep::Error, 'Subclass responsibility'
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -6,7 +6,6 @@ module Blacksheep
|
|
6
6
|
attr_reader :case, :params
|
7
7
|
|
8
8
|
def call(params, **options)
|
9
|
-
puts transformer: "*" * 50
|
10
9
|
detect_case(params)
|
11
10
|
|
12
11
|
transformed_params = self.transformed_params(params)
|
@@ -15,7 +14,7 @@ module Blacksheep
|
|
15
14
|
|
16
15
|
transformed_json = transform_result(json)
|
17
16
|
|
18
|
-
|
17
|
+
ActionResult.new(transformed_json, :ok)
|
19
18
|
end
|
20
19
|
|
21
20
|
def perform(params, current_user: nil, **options, &block)
|
@@ -26,7 +25,7 @@ module Blacksheep
|
|
26
25
|
json = block.call(transformed_params)
|
27
26
|
transformed_json = transform_result(json)
|
28
27
|
|
29
|
-
|
28
|
+
ActionResult.new(transformed_json, :ok)
|
30
29
|
end
|
31
30
|
|
32
31
|
|
@@ -42,7 +41,7 @@ module Blacksheep
|
|
42
41
|
when 'camel'
|
43
42
|
snakecase_keys(params)
|
44
43
|
else
|
45
|
-
raise
|
44
|
+
raise Blacksheep::Error, "unknown_case #{@case}"
|
46
45
|
end
|
47
46
|
end
|
48
47
|
|
@@ -54,14 +53,22 @@ module Blacksheep
|
|
54
53
|
# @return [Array, Hash] The rsult structure with keys converted to source caseing
|
55
54
|
# @see #camelize_keys
|
56
55
|
def transform_result(obj)
|
57
|
-
|
56
|
+
is_action_result, data = if obj.kind_of?(Blacksheep::ActionResult)
|
57
|
+
[ true, obj.data ]
|
58
|
+
else
|
59
|
+
[ false, obj ]
|
60
|
+
end
|
61
|
+
|
62
|
+
converted_data = case @case
|
58
63
|
when 'snake', 'as_is'
|
59
|
-
|
64
|
+
data
|
60
65
|
when 'camel'
|
61
|
-
camelize_keys(
|
66
|
+
camelize_keys(data)
|
62
67
|
else
|
63
|
-
raise
|
68
|
+
raise Blacksheep::Error, "unknown_case #{@case}"
|
64
69
|
end
|
70
|
+
|
71
|
+
is_action_result ? obj.set_data(converted_data) : converted_data
|
65
72
|
end
|
66
73
|
|
67
74
|
#
|
@@ -5,19 +5,19 @@ module Blacksheep
|
|
5
5
|
# @class Blacksheep::Decorators::ResultMatcher
|
6
6
|
class ResultMatcher < ActionDecorator
|
7
7
|
Matcher = -> {
|
8
|
-
# Match `
|
9
|
-
success_case = Dry::Matcher::Case.new do |
|
10
|
-
if
|
11
|
-
|
8
|
+
# Match `action_result` with status :ok for success
|
9
|
+
success_case = Dry::Matcher::Case.new do |action_result, _|
|
10
|
+
if action_result.success?
|
11
|
+
action_result
|
12
12
|
else
|
13
13
|
# this is a constant from dry/core/constants
|
14
14
|
Dry::Matcher::Undefined
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
# Match `
|
19
|
-
failure_case = Dry::Matcher::Case.new do |
|
20
|
-
if !
|
18
|
+
# Match `action_result` with status not :ok` for failure - other status' can be distinguished
|
19
|
+
failure_case = Dry::Matcher::Case.new do |action_result, patterns|
|
20
|
+
if !action_result.success! && (patterns.empty? || patterns.include?(action_result.status))
|
21
21
|
value
|
22
22
|
else
|
23
23
|
Dry::Matcher::Undefined
|
@@ -31,12 +31,11 @@ module Blacksheep
|
|
31
31
|
include Dry::Matcher.for(:call, with: Matcher)
|
32
32
|
|
33
33
|
def call(*)
|
34
|
-
puts matcher: "*" * 50
|
35
34
|
super
|
36
35
|
end
|
37
36
|
|
38
37
|
def perform(*)
|
39
|
-
raise
|
38
|
+
raise Blacksheep::Error, 'ResultMatcher does not support #perform'
|
40
39
|
end
|
41
40
|
|
42
41
|
end
|
data/lib/blacksheep/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: blacksheep
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Schweizer
|
@@ -87,12 +87,12 @@ files:
|
|
87
87
|
- lib/blacksheep.rb
|
88
88
|
- lib/blacksheep/action.rb
|
89
89
|
- lib/blacksheep/action_decorator.rb
|
90
|
+
- lib/blacksheep/action_result.rb
|
90
91
|
- lib/blacksheep/decorators/default_error_handler.rb
|
92
|
+
- lib/blacksheep/decorators/error_handler.rb
|
91
93
|
- lib/blacksheep/decorators/json_transformer.rb
|
92
94
|
- lib/blacksheep/decorators/localizer.rb
|
93
95
|
- lib/blacksheep/decorators/result_matcher.rb
|
94
|
-
- lib/blacksheep/json_meta.rb
|
95
|
-
- lib/blacksheep/json_result.rb
|
96
96
|
- lib/blacksheep/version.rb
|
97
97
|
homepage: http://verticonaut.me
|
98
98
|
licenses:
|
data/lib/blacksheep/json_meta.rb
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
module Blacksheep
|
2
|
-
class JsonMeta
|
3
|
-
|
4
|
-
attr_reader :json
|
5
|
-
|
6
|
-
def initialize(json = {})
|
7
|
-
@json = json
|
8
|
-
end
|
9
|
-
|
10
|
-
class << self
|
11
|
-
def success(title: nil, detail: nil)
|
12
|
-
new.success(title: title, detail: detail)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def success(title: nil, detail: nil)
|
17
|
-
result = {
|
18
|
-
success: true,
|
19
|
-
}
|
20
|
-
|
21
|
-
if title.present?
|
22
|
-
result[:title] = title
|
23
|
-
elsif detail.present?
|
24
|
-
result[:title] = 'Success'
|
25
|
-
end
|
26
|
-
|
27
|
-
result[:detail] = detail if detail.present?
|
28
|
-
|
29
|
-
json[:result] = result
|
30
|
-
|
31
|
-
self
|
32
|
-
end
|
33
|
-
|
34
|
-
def as_json
|
35
|
-
{
|
36
|
-
jsonMeta: json
|
37
|
-
}
|
38
|
-
end
|
39
|
-
|
40
|
-
end
|
41
|
-
end
|