evil-client 0.3.3 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.codeclimate.yml +0 -11
- data/.gitignore +1 -0
- data/.rspec +0 -1
- data/.rubocop.yml +22 -19
- data/.travis.yml +1 -0
- data/CHANGELOG.md +251 -6
- data/LICENSE.txt +3 -1
- data/README.md +47 -81
- data/docs/helpers/body.md +93 -0
- data/docs/helpers/connection.md +19 -0
- data/docs/helpers/headers.md +72 -0
- data/docs/helpers/http_method.md +39 -0
- data/docs/helpers/let.md +14 -0
- data/docs/helpers/logger.md +24 -0
- data/docs/helpers/middleware.md +56 -0
- data/docs/helpers/operation.md +103 -0
- data/docs/helpers/option.md +50 -0
- data/docs/helpers/path.md +37 -0
- data/docs/helpers/query.md +59 -0
- data/docs/helpers/response.md +40 -0
- data/docs/helpers/scope.md +121 -0
- data/docs/helpers/security.md +102 -0
- data/docs/helpers/validate.md +68 -0
- data/docs/index.md +70 -78
- data/docs/license.md +5 -1
- data/docs/rspec.md +96 -0
- data/evil-client.gemspec +10 -8
- data/lib/evil/client.rb +126 -72
- data/lib/evil/client/builder.rb +47 -0
- data/lib/evil/client/builder/operation.rb +40 -0
- data/lib/evil/client/builder/scope.rb +31 -0
- data/lib/evil/client/chaining.rb +17 -0
- data/lib/evil/client/connection.rb +60 -20
- data/lib/evil/client/container.rb +66 -0
- data/lib/evil/client/container/operation.rb +23 -0
- data/lib/evil/client/container/scope.rb +28 -0
- data/lib/evil/client/exceptions/definition_error.rb +15 -0
- data/lib/evil/client/exceptions/name_error.rb +32 -0
- data/lib/evil/client/exceptions/response_error.rb +42 -0
- data/lib/evil/client/exceptions/type_error.rb +29 -0
- data/lib/evil/client/exceptions/validation_error.rb +27 -0
- data/lib/evil/client/formatter.rb +49 -0
- data/lib/evil/client/formatter/form.rb +45 -0
- data/lib/evil/client/formatter/multipart.rb +33 -0
- data/lib/evil/client/formatter/part.rb +66 -0
- data/lib/evil/client/formatter/text.rb +21 -0
- data/lib/evil/client/resolver.rb +84 -0
- data/lib/evil/client/resolver/body.rb +22 -0
- data/lib/evil/client/resolver/format.rb +30 -0
- data/lib/evil/client/resolver/headers.rb +46 -0
- data/lib/evil/client/resolver/http_method.rb +34 -0
- data/lib/evil/client/resolver/middleware.rb +36 -0
- data/lib/evil/client/resolver/query.rb +39 -0
- data/lib/evil/client/resolver/request.rb +96 -0
- data/lib/evil/client/resolver/response.rb +26 -0
- data/lib/evil/client/resolver/security.rb +113 -0
- data/lib/evil/client/resolver/uri.rb +35 -0
- data/lib/evil/client/rspec.rb +127 -0
- data/lib/evil/client/schema.rb +105 -0
- data/lib/evil/client/schema/operation.rb +177 -0
- data/lib/evil/client/schema/scope.rb +73 -0
- data/lib/evil/client/settings.rb +172 -0
- data/lib/evil/client/settings/validator.rb +64 -0
- data/mkdocs.yml +21 -15
- data/spec/features/custom_connection_spec.rb +17 -0
- data/spec/features/operation/middleware_spec.rb +50 -0
- data/spec/features/operation/options_spec.rb +71 -0
- data/spec/features/operation/request_spec.rb +94 -0
- data/spec/features/operation/response_spec.rb +48 -0
- data/spec/features/scope/options_spec.rb +52 -0
- data/spec/fixtures/locales/en.yml +16 -0
- data/spec/fixtures/test_client.rb +76 -0
- data/spec/spec_helper.rb +18 -6
- data/spec/support/fixtures_helper.rb +7 -0
- data/spec/unit/builder/operation_spec.rb +90 -0
- data/spec/unit/builder/scope_spec.rb +84 -0
- data/spec/unit/client_spec.rb +137 -0
- data/spec/unit/connection_spec.rb +78 -0
- data/spec/unit/container/operation_spec.rb +81 -0
- data/spec/unit/container/scope_spec.rb +61 -0
- data/spec/unit/container_spec.rb +107 -0
- data/spec/unit/exceptions/definition_error_spec.rb +15 -0
- data/spec/unit/exceptions/name_error_spec.rb +77 -0
- data/spec/unit/exceptions/response_error_spec.rb +22 -0
- data/spec/unit/exceptions/type_error_spec.rb +71 -0
- data/spec/unit/exceptions/validation_error_spec.rb +13 -0
- data/spec/unit/formatter/form_spec.rb +27 -0
- data/spec/unit/formatter/multipart_spec.rb +23 -0
- data/spec/unit/formatter/part_spec.rb +49 -0
- data/spec/unit/formatter/text_spec.rb +37 -0
- data/spec/unit/formatter_spec.rb +46 -0
- data/spec/unit/resolver/body_spec.rb +65 -0
- data/spec/unit/resolver/format_spec.rb +66 -0
- data/spec/unit/resolver/headers_spec.rb +93 -0
- data/spec/unit/resolver/http_method_spec.rb +67 -0
- data/spec/unit/resolver/middleware_spec.rb +83 -0
- data/spec/unit/resolver/query_spec.rb +85 -0
- data/spec/unit/resolver/request_spec.rb +121 -0
- data/spec/unit/resolver/response_spec.rb +64 -0
- data/spec/unit/resolver/security_spec.rb +156 -0
- data/spec/unit/resolver/uri_spec.rb +117 -0
- data/spec/unit/rspec_spec.rb +342 -0
- data/spec/unit/schema/operation_spec.rb +309 -0
- data/spec/unit/schema/scope_spec.rb +110 -0
- data/spec/unit/schema_spec.rb +157 -0
- data/spec/unit/settings/validator_spec.rb +128 -0
- data/spec/unit/settings_spec.rb +248 -0
- metadata +192 -135
- data/docs/base_url.md +0 -38
- data/docs/documentation.md +0 -9
- data/docs/headers.md +0 -59
- data/docs/http_method.md +0 -31
- data/docs/model.md +0 -173
- data/docs/operation.md +0 -0
- data/docs/overview.md +0 -0
- data/docs/path.md +0 -48
- data/docs/query.md +0 -99
- data/docs/responses.md +0 -66
- data/docs/security.md +0 -102
- data/docs/settings.md +0 -32
- data/lib/evil/client/connection/net_http.rb +0 -57
- data/lib/evil/client/dsl.rb +0 -127
- data/lib/evil/client/dsl/base.rb +0 -26
- data/lib/evil/client/dsl/files.rb +0 -37
- data/lib/evil/client/dsl/headers.rb +0 -16
- data/lib/evil/client/dsl/http_method.rb +0 -24
- data/lib/evil/client/dsl/operation.rb +0 -91
- data/lib/evil/client/dsl/operations.rb +0 -41
- data/lib/evil/client/dsl/path.rb +0 -25
- data/lib/evil/client/dsl/query.rb +0 -16
- data/lib/evil/client/dsl/response.rb +0 -61
- data/lib/evil/client/dsl/responses.rb +0 -29
- data/lib/evil/client/dsl/scope.rb +0 -27
- data/lib/evil/client/dsl/security.rb +0 -57
- data/lib/evil/client/dsl/verifier.rb +0 -35
- data/lib/evil/client/middleware.rb +0 -81
- data/lib/evil/client/middleware/base.rb +0 -11
- data/lib/evil/client/middleware/merge_security.rb +0 -20
- data/lib/evil/client/middleware/normalize_headers.rb +0 -17
- data/lib/evil/client/middleware/stringify_form.rb +0 -40
- data/lib/evil/client/middleware/stringify_json.rb +0 -19
- data/lib/evil/client/middleware/stringify_multipart.rb +0 -36
- data/lib/evil/client/middleware/stringify_multipart/part.rb +0 -36
- data/lib/evil/client/middleware/stringify_query.rb +0 -35
- data/lib/evil/client/operation.rb +0 -34
- data/lib/evil/client/operation/request.rb +0 -26
- data/lib/evil/client/operation/response.rb +0 -39
- data/lib/evil/client/operation/response_error.rb +0 -13
- data/lib/evil/client/operation/unexpected_response_error.rb +0 -19
- data/spec/features/instantiation_spec.rb +0 -68
- data/spec/features/middleware_spec.rb +0 -79
- data/spec/features/operation_with_documentation_spec.rb +0 -41
- data/spec/features/operation_with_files_spec.rb +0 -40
- data/spec/features/operation_with_form_body_spec.rb +0 -158
- data/spec/features/operation_with_headers_spec.rb +0 -99
- data/spec/features/operation_with_http_method_spec.rb +0 -45
- data/spec/features/operation_with_json_body_spec.rb +0 -156
- data/spec/features/operation_with_nested_responses_spec.rb +0 -95
- data/spec/features/operation_with_path_spec.rb +0 -47
- data/spec/features/operation_with_query_spec.rb +0 -84
- data/spec/features/operation_with_security_spec.rb +0 -228
- data/spec/features/scoping_spec.rb +0 -48
- data/spec/support/test_client.rb +0 -15
- data/spec/unit/evil/client/connection/net_http_spec.rb +0 -38
- data/spec/unit/evil/client/dsl/files_spec.rb +0 -37
- data/spec/unit/evil/client/dsl/operation_spec.rb +0 -374
- data/spec/unit/evil/client/dsl/operations_spec.rb +0 -29
- data/spec/unit/evil/client/dsl/scope_spec.rb +0 -32
- data/spec/unit/evil/client/dsl/security_spec.rb +0 -135
- data/spec/unit/evil/client/middleware/merge_security_spec.rb +0 -32
- data/spec/unit/evil/client/middleware/normalize_headers_spec.rb +0 -17
- data/spec/unit/evil/client/middleware/stringify_form_spec.rb +0 -63
- data/spec/unit/evil/client/middleware/stringify_json_spec.rb +0 -61
- data/spec/unit/evil/client/middleware/stringify_multipart/part_spec.rb +0 -59
- data/spec/unit/evil/client/middleware/stringify_multipart_spec.rb +0 -62
- data/spec/unit/evil/client/middleware/stringify_query_spec.rb +0 -40
- data/spec/unit/evil/client/middleware_spec.rb +0 -46
- data/spec/unit/evil/client/operation/request_spec.rb +0 -49
- data/spec/unit/evil/client/operation/response_spec.rb +0 -63
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1a0f6860291b235077bd6d9063eb9e1ec47cb9ef
|
4
|
+
data.tar.gz: cbb9aca48a0283cf8e6ec84bec9444ea74bb440c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c1d2c2e407c90ef12db1d58c4aed5fef1a4c851934f90e25602ad5461c14278e30dcd3a1dbc7534dc17218797d46dedaa8f023389be46625f66bb046a06791a5
|
7
|
+
data.tar.gz: 433099e8dcebb8e48e0f22f057db11c68eb78556a1660508bdd22a261a40ad2c59407971459716c027d7c5d4b7cf122b2c03fa63d3308b06762e5658f3e7d763
|
data/.codeclimate.yml
CHANGED
@@ -2,17 +2,6 @@
|
|
2
2
|
engines:
|
3
3
|
rubocop:
|
4
4
|
enabled: true
|
5
|
-
checks:
|
6
|
-
Rubocop/Style/FrozenStringLiteralComment:
|
7
|
-
enabled: false
|
8
|
-
Rubocop/Style/Documentation:
|
9
|
-
enabled: false
|
10
|
-
Rubocop/Style/ClassAndModuleChildren:
|
11
|
-
enabled: false
|
12
|
-
Rubocop/Style/SpaceInLambdaLiteral:
|
13
|
-
enabled: false
|
14
|
-
Style/SingleLineBlockParams:
|
15
|
-
enabled: false
|
16
5
|
ratings:
|
17
6
|
paths:
|
18
7
|
- "lib/**.rb"
|
data/.gitignore
CHANGED
data/.rspec
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,41 +1,44 @@
|
|
1
1
|
---
|
2
2
|
AllCops:
|
3
|
-
DisplayCopNames:
|
4
|
-
|
5
|
-
StyleGuideCopsOnly: true
|
6
|
-
TargetRubyVersion: 2.3
|
3
|
+
DisplayCopNames: true
|
4
|
+
TargetRubyVersion: 2.3
|
7
5
|
|
8
|
-
|
6
|
+
Lint/AmbiguousBlockAssociation:
|
9
7
|
Enabled: false
|
10
8
|
|
11
|
-
|
9
|
+
Metrics/BlockLength:
|
12
10
|
Enabled: false
|
13
11
|
|
14
|
-
Style/
|
15
|
-
Exclude:
|
16
|
-
- lib/evil-client.rb
|
17
|
-
|
18
|
-
Style/Lambda:
|
12
|
+
Style/Alias:
|
19
13
|
Enabled: false
|
20
14
|
|
21
|
-
Style/
|
15
|
+
Style/ClassAndModuleChildren:
|
22
16
|
Enabled: false
|
23
17
|
|
24
|
-
Style/
|
25
|
-
Enabled: false
|
26
|
-
|
27
|
-
Style/MultilineMethodCallIndentation:
|
18
|
+
Style/FileName:
|
28
19
|
Exclude:
|
29
|
-
-
|
20
|
+
- lib/evil-client.rb
|
30
21
|
|
31
|
-
Style/
|
22
|
+
Style/FrozenStringLiteralComment:
|
23
|
+
Enabled: false
|
24
|
+
|
25
|
+
Style/ModuleFunction:
|
32
26
|
Enabled: false
|
33
27
|
|
34
28
|
Style/RaiseArgs:
|
35
29
|
Enabled: false
|
36
30
|
|
37
31
|
Style/RescueModifier:
|
38
|
-
|
32
|
+
Exclude:
|
33
|
+
- '**/*_spec.rb'
|
34
|
+
|
35
|
+
Style/Semicolon:
|
36
|
+
Exclude:
|
37
|
+
- '**/*_spec.rb'
|
39
38
|
|
40
39
|
Style/StringLiterals:
|
41
40
|
EnforcedStyle: double_quotes
|
41
|
+
|
42
|
+
Style/SingleLineMethods:
|
43
|
+
Exclude:
|
44
|
+
- '**/*_spec.rb'
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -4,9 +4,254 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog], and this project adheres
|
5
5
|
to [Semantic Versioning].
|
6
6
|
|
7
|
-
## [0.
|
7
|
+
## [1.0.0] [2017-08-06]
|
8
|
+
|
9
|
+
This is a total new reincarnation of the gem. I've changed its
|
10
|
+
architecture for consistency and unification reasons. This version is
|
11
|
+
backward-incompatible to all the previous ones up to the [0.3.3].
|
12
|
+
|
13
|
+
Its DSL was re-written and regularized as well. While the idea of the gem
|
14
|
+
remains about the same as before, its implementation has been changed
|
15
|
+
drastically in many important details.
|
16
|
+
|
17
|
+
### [BREAKING] Changed
|
18
|
+
|
19
|
+
- There is no more differencies between "root" DSL, DSL of scope and
|
20
|
+
operation. All scopes use exactly the same methods. All operations
|
21
|
+
uses just the same methods except for `#operation` and `#scope` that
|
22
|
+
provide further nesting.
|
23
|
+
|
24
|
+
Any customization (inside a sub-scope or operation of some scope)
|
25
|
+
re-loads previous definitions in the following order:
|
26
|
+
|
27
|
+
```text
|
28
|
+
root operation(anonymous)
|
29
|
+
subscope operation(anonymous)
|
30
|
+
# ...
|
31
|
+
custom(named) operation
|
32
|
+
```
|
33
|
+
|
34
|
+
- Unlike previous versions every named operation belongs to some scope
|
35
|
+
(possibly nested into parents ones). Operations/subscopes should
|
36
|
+
have unique names inside its scope only (no more global namespace
|
37
|
+
for all operations).
|
38
|
+
|
39
|
+
Every scope knows the list of its subscopes and operations like:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
MyClient.new.scopes[:users].operations[:fetch]
|
43
|
+
```
|
44
|
+
|
45
|
+
- You can describe operations step-by-step. For example, you have
|
46
|
+
to describe `path` of root anonymous operation. Later you can add subpath
|
47
|
+
in the corresponding operation or scope:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
class MyClient
|
51
|
+
option :subdomain
|
52
|
+
path { "https://#{subdomain}.foobar.com" } # same as base_path
|
53
|
+
|
54
|
+
scope :users do
|
55
|
+
option :version
|
56
|
+
|
57
|
+
# makes full path "https://{subdomain}.foobar.com/v{version}/users"
|
58
|
+
path { "v#{version}/users" }
|
59
|
+
|
60
|
+
operation :fetch do
|
61
|
+
option :id
|
62
|
+
|
63
|
+
# the final path: "https://{subdomain}.foobar.com/v{version}/users/{id}"
|
64
|
+
path { id }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
```
|
69
|
+
|
70
|
+
- As a syntax sugar all undefined methods are delegated to subscopes
|
71
|
+
and operations.
|
72
|
+
|
73
|
+
Instead of full syntax:
|
74
|
+
|
75
|
+
```ruby
|
76
|
+
MyClient.new
|
77
|
+
.scopes[:users][version: "1.1"]
|
78
|
+
.operations[:fetch][id: 7]
|
79
|
+
.call
|
80
|
+
```
|
81
|
+
|
82
|
+
You can use more natural one:
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
MyClient.new.users(version: "1.1").fetch(id: 7)
|
86
|
+
```
|
87
|
+
|
88
|
+
- Every scope or operation takes some options.
|
89
|
+
Defined options are inherited and collected from the very root of the client:
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
client = MyClient.new token: "foo", bar: :baz
|
93
|
+
client.options # => { token: "foo" }
|
94
|
+
|
95
|
+
users = client.users(version: 3)
|
96
|
+
users.options # => { token: "foo", version: 3 }
|
97
|
+
|
98
|
+
fetch = users.operations[:fetch][id: 7]
|
99
|
+
fetch.options # => { token: "foo", version: 3, id: 7 }
|
100
|
+
```
|
101
|
+
|
102
|
+
- You can reload assigned options at any level of nesting
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
users.options # => { token: "foo", version: 3 }
|
106
|
+
|
107
|
+
fetch = users.operations[:fetch][id: 7, token: "baz"]
|
108
|
+
fetch.options # => { token: "baz", version: 3, id: 7 }
|
109
|
+
```
|
110
|
+
|
111
|
+
- When adding an option you can define the necessary coercers, default values
|
112
|
+
and requirements using the [dry-initializer] gem API.
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
class MyClient
|
116
|
+
option :token, proc(&:to_s) # required
|
117
|
+
option :subdomain, proc(&:to_s), default: { "europe" }
|
118
|
+
end
|
119
|
+
```
|
120
|
+
|
121
|
+
- In addition you can define validator to check whether options
|
122
|
+
correspond to each other:
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
class MyClient
|
126
|
+
option :token, optional: true
|
127
|
+
option :password, optional: true
|
128
|
+
|
129
|
+
validate(:valid_credentials) { token.nil? ^ password.nil? }
|
130
|
+
end
|
131
|
+
```
|
132
|
+
|
133
|
+
You have to add i18n localization for that errors:
|
134
|
+
|
135
|
+
```yaml
|
136
|
+
# config/locales/evil-client.en.yml
|
137
|
+
en:
|
138
|
+
evil:
|
139
|
+
client:
|
140
|
+
errors:
|
141
|
+
my_client:
|
142
|
+
valid_credentials: "You should set either token or password"
|
143
|
+
```
|
144
|
+
|
145
|
+
All validations from root will be applied at every single instance
|
146
|
+
(of subscope or operation). Every time we validate current (reloaded) options.
|
147
|
+
|
148
|
+
- The method `let` allows to define custom memoizers:
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
class MyClient
|
152
|
+
option :first_name, proc(&:to_s)
|
153
|
+
option :last_name, proc(&:to_s)
|
154
|
+
|
155
|
+
let(:full_name) { [first_name, last_name].join(" ") }
|
156
|
+
end
|
157
|
+
```
|
158
|
+
|
159
|
+
Such memoizers are available in validators and request/response declarations.
|
160
|
+
|
161
|
+
- Definitions of request/response parts can be made ether as a plain values
|
162
|
+
|
163
|
+
```ruby
|
164
|
+
class MyClient
|
165
|
+
path "https://api.example.com"
|
166
|
+
end
|
167
|
+
```
|
8
168
|
|
9
|
-
|
169
|
+
or via blocks:
|
170
|
+
|
171
|
+
```ruby
|
172
|
+
class MyClient
|
173
|
+
option :subdomain
|
174
|
+
|
175
|
+
path { "https://#{subdomain}.example.com" }
|
176
|
+
end
|
177
|
+
```
|
178
|
+
|
179
|
+
Inside the block you can access all the current options.
|
180
|
+
|
181
|
+
- Some upper-level operation definitions (path, query, and headers)
|
182
|
+
are updated by nested definitions, while the others (http_method, format,
|
183
|
+
security settings, request body, and response handler) will be reloaded.
|
184
|
+
|
185
|
+
For example, you can define some shared headers at the client (root) level,
|
186
|
+
then add some scope/operation-specific headers later. Or you can define
|
187
|
+
security schema by default, and reload it for a specific operation.
|
188
|
+
|
189
|
+
- I found customization of underlying client an overkill. That's why
|
190
|
+
all clients will be based on the same old Net::HTTP(S) connection.
|
191
|
+
|
192
|
+
But the client connection is just the object with the only required method
|
193
|
+
`#call` taking rack-compatible env, and returning rack-compatible response.
|
194
|
+
|
195
|
+
You can define your own connection for a client:
|
196
|
+
|
197
|
+
```ruby
|
198
|
+
my_connection = double call: [200, {}, []]
|
199
|
+
|
200
|
+
class MyClient
|
201
|
+
connection = my_connection
|
202
|
+
end
|
203
|
+
```
|
204
|
+
|
205
|
+
- You can define a middleware for every single operation -- exactly
|
206
|
+
in the same way as other parts of operation specification.
|
207
|
+
|
208
|
+
All middleware will be used in the order of their definition:
|
209
|
+
|
210
|
+
```ruby
|
211
|
+
class MyClient
|
212
|
+
middleware Foo
|
213
|
+
|
214
|
+
scope :users do
|
215
|
+
middleware { [Bar, Baz] }
|
216
|
+
end
|
217
|
+
end
|
218
|
+
```
|
219
|
+
|
220
|
+
In the above example rack env will be sent to Foo -> Bar -> Baz -> Connection,
|
221
|
+
and rack response will be processed by Connection -> Baz -> Bar -> Foo.
|
222
|
+
|
223
|
+
- I've simplified some definitions in the OperationDSL.
|
224
|
+
|
225
|
+
Now you should define `headers` and `query` as a simple hashes (no helpers).
|
226
|
+
That hashes will be merged to upper-level ones (that's how we customize them).
|
227
|
+
|
228
|
+
You can also define body as either hash, or IO (for files), depending
|
229
|
+
on request format.
|
230
|
+
|
231
|
+
You have to define a format for operation via special `format` helper
|
232
|
+
(:json by default, :form, :text, :multipart are available as well):
|
233
|
+
|
234
|
+
```
|
235
|
+
operation :upload do
|
236
|
+
option :multipart, default: proc { File.new "Hi!" }
|
237
|
+
|
238
|
+
format { :files } # :json (default), :text, and :form are supported as well
|
239
|
+
body { [StringIO.new, "Hi!"] }
|
240
|
+
end
|
241
|
+
```
|
242
|
+
|
243
|
+
Because `format` takes a block, you can customize its value depending
|
244
|
+
on any option(s).
|
245
|
+
|
246
|
+
- Response handlers take a block with rack request: [status, headers, [body]]
|
247
|
+
|
248
|
+
There is no dsl for processing that responses (because it can be anything).
|
249
|
+
You don't need to provide models (but you can do it on your own), or
|
250
|
+
validate responses in any special way. Do your best!
|
251
|
+
|
252
|
+
- No more dependencies from both the `dry-types` and `evil-struct`.
|
253
|
+
|
254
|
+
## [0.3.3] - [2017-07-14]
|
10
255
|
|
11
256
|
### Fixed
|
12
257
|
- dependency from 'securerandom' standard library (nepalez)
|
@@ -16,8 +261,6 @@ On the road to v0.3.3
|
|
16
261
|
|
17
262
|
# [0.3.2] - [2016-11-29]
|
18
263
|
|
19
|
-
On the road to v0.4.0
|
20
|
-
|
21
264
|
### Fixed
|
22
265
|
- Query and body encoding (nepalez)
|
23
266
|
|
@@ -36,7 +279,7 @@ On the road to v0.4.0
|
|
36
279
|
|
37
280
|
This version changes the way of processing responses. Instead of dealing
|
38
281
|
with raw rake responses, we add opinionated methods to gracefully process
|
39
|
-
responses from JSON or
|
282
|
+
responses from JSON or form text.
|
40
283
|
|
41
284
|
In the next minor versions processors for both "form" and "file" (multipart)
|
42
285
|
formats will be added.
|
@@ -59,7 +302,7 @@ formats will be added.
|
|
59
302
|
|
60
303
|
This time response handler will try processing a response using various
|
61
304
|
definitions (in order of their declaration) until some suits. The hanlder
|
62
|
-
returns `
|
305
|
+
returns `ResponseError` in case no definition proves suitable.
|
63
306
|
|
64
307
|
Names (the first param) are unique. When several definitions use the same name,
|
65
308
|
only the last one will be applicable.
|
@@ -83,8 +326,10 @@ formats will be added.
|
|
83
326
|
response :not_found, 404, format: "json", raise: true
|
84
327
|
```
|
85
328
|
|
329
|
+
[1.0.0]: https://github.com/evilmartians/evil-client/compare/v0.3.3...v1.0.0
|
86
330
|
[0.3.3]: https://github.com/evilmartians/evil-client/compare/v0.3.2...v0.3.3
|
87
331
|
[0.3.2]: https://github.com/evilmartians/evil-client/compare/v0.3.1...v0.3.2
|
88
332
|
[0.3.1]: https://github.com/evilmartians/evil-client/compare/v0.3.0...v0.3.1
|
89
333
|
[Keep a Changelog]: http://keepachangelog.com/
|
90
334
|
[Semantic Versioning]: http://semver.org/
|
335
|
+
[dry-initializer]: http://github.com/dry-rb/dry-initalizer
|
data/LICENSE.txt
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
The MIT License (MIT)
|
2
2
|
|
3
|
-
Copyright (c)
|
3
|
+
Copyright (c) 2015-2017 Andrew Kozin (nepalez),
|
4
|
+
Ravil Bairamgalin (brainopia),
|
5
|
+
Evil Martians (evilmartians)
|
4
6
|
|
5
7
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
8
|
of this software and associated documentation files (the "Software"), to deal
|
data/README.md
CHANGED
@@ -13,15 +13,7 @@ Human-friendly DSL for writing HTTP(s) clients in Ruby
|
|
13
13
|
|
14
14
|
## Intro
|
15
15
|
|
16
|
-
The gem allows writing http(s) clients in a way
|
17
|
-
|
18
|
-
The gem stands away from mutable states and monkey patching when possible. To support multithreading all instances are immutable (though not frozen to avoid performance loss). Its DSL is backed on top of [dry-initializer][dry-initializer] gem, and supposes heavy usage of [dry-types][dry-types] system of contracts.
|
19
|
-
|
20
|
-
For now the DSL supports clients to **json** and **form data** APIs out of the box. Because of high variance of XML-based APIs, building corresponding clients require more efforts on a middleware level.
|
21
|
-
|
22
|
-
[swagger]: http://swagger.io
|
23
|
-
[dry-initializer]: http://dry-rb.org/gems/dry-initializer
|
24
|
-
[dry-types]: http://dry-rb.org/gems/dry-types
|
16
|
+
The gem allows writing http(s) clients in a way inspired by [Swagger][swagger] specifications. It stands away from mutable states and monkey patching when possible. To support multithreading all instances are immutable (though not frozen to avoid performance loss).
|
25
17
|
|
26
18
|
## Installation
|
27
19
|
|
@@ -45,97 +37,69 @@ $ gem install evil-client
|
|
45
37
|
|
46
38
|
## Synopsis
|
47
39
|
|
48
|
-
The following example gives an idea of how a client to remote API looks like when written on top of `Evil::Client
|
40
|
+
The following example gives an idea of how a client to remote API looks like when written on top of `Evil::Client`.
|
49
41
|
|
50
42
|
```ruby
|
51
43
|
require "evil-client"
|
52
|
-
require "dry-types"
|
53
44
|
|
54
45
|
class CatsClient < Evil::Client
|
55
|
-
#
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
attribute :age, Dry::Types["coercible.int"], default: proc { 0 }
|
60
|
-
end
|
61
|
-
|
62
|
-
# Define settings the client initialized with
|
63
|
-
# The settings parameterizes operations when necessary
|
64
|
-
settings do
|
65
|
-
param :domain, Dry::Types["strict.string"] # required!
|
66
|
-
option :version, Dry::Types["coercible.int"], default: proc { 0 }
|
67
|
-
option :user, Dry::Types["strict.string"] # required!
|
68
|
-
option :password, Dry::Types["strict.string"] # required!
|
69
|
-
end
|
70
|
-
|
71
|
-
# Define a base url using
|
72
|
-
base_url do |settings|
|
73
|
-
"https://#{settings.domain}.example.com/api/v#{settings.version}/"
|
74
|
-
end
|
46
|
+
# Define options for the client's initializer
|
47
|
+
option :domain, proc(&:to_s)
|
48
|
+
option :user, proc(&:to_s)
|
49
|
+
option :password, proc(&:to_s)
|
75
50
|
|
76
51
|
# Definitions shared by all operations
|
77
|
-
|
78
|
-
|
79
|
-
end
|
80
|
-
|
81
|
-
# Operation-specific definition to update a cat by id
|
82
|
-
# This provides low-level DSL `operations[:update_cat].call`
|
83
|
-
operation :update_cat do |settings|
|
84
|
-
http_method :patch
|
85
|
-
path { |id:, **| "cats/#{id}" } # id will be taken from request parameters
|
86
|
-
|
87
|
-
body format: "json" do
|
88
|
-
attributes optional: true do
|
89
|
-
attribute :name
|
90
|
-
attribute :color
|
91
|
-
attribute :age
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
# Parses json response and wraps it into Cat instance with additional
|
96
|
-
# parameter
|
97
|
-
response 200, format: :json, model: Cat do
|
98
|
-
attribute :success # add response-specific attribute to the cat
|
99
|
-
end
|
100
|
-
|
101
|
-
# Parses json response, wraps it into model with [#error] and raises
|
102
|
-
# an exception where [ResponseError#response] contains the model istance
|
103
|
-
response 422, format: :json, raise: true do
|
104
|
-
attribute :error
|
105
|
-
end
|
52
|
+
path { "https://#{domain}.example.com/api" }
|
53
|
+
security { basic_auth settings.user, settings.password }
|
106
54
|
|
107
|
-
# Takes raw body and converts it into the hashie
|
108
|
-
response 404, raise: true do |body|
|
109
|
-
Hashie::Mash.new error: body
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
113
|
-
# Add top-level DSL
|
114
55
|
scope :cats do
|
115
|
-
|
116
|
-
|
117
|
-
|
56
|
+
# Scope-specific definitions
|
57
|
+
option :version, default: proc { 1 }
|
58
|
+
path { "v#{version}" } # subpath added to root path
|
59
|
+
|
60
|
+
# Operation-specific definitions to update a cat by id
|
61
|
+
operation :update do
|
62
|
+
option :id, proc(&:to_i)
|
63
|
+
option :name, optional: true
|
64
|
+
option :color, optional: true
|
65
|
+
option :age, optional: true
|
66
|
+
|
67
|
+
let(:data) { options.select { |key, _| %i(name color age).include? key } }
|
68
|
+
validate(:data_present) { !data.empty? }
|
69
|
+
|
70
|
+
path { "cats/#{id}" } # added to root path
|
71
|
+
http_method :patch # you can use plain syntax instead of a block
|
72
|
+
format "json"
|
73
|
+
body { options.reject { |key, _val| key == :id } }
|
74
|
+
|
75
|
+
# Parses json response and wraps it into Cat instance with additional
|
76
|
+
# parameter
|
77
|
+
response 200 do |(status, headers, body)|
|
78
|
+
# Suppose you define a model for cats
|
79
|
+
Cat.new JSON.parse(body)
|
118
80
|
end
|
81
|
+
|
82
|
+
# Parses json response, wraps it into model with [#error] and raises
|
83
|
+
# an exception where [ResponseError#response] contains the model istance
|
84
|
+
response(400, 422) { |(status, *)| raise "#{status}: Record invalid" }
|
119
85
|
end
|
120
86
|
end
|
121
87
|
end
|
122
88
|
|
123
|
-
# Instantiate a client with concrete settings
|
124
|
-
cat_client = CatClient.new "awesome-cats",
|
125
|
-
|
126
|
-
user: "cat_lover",
|
89
|
+
# Instantiate a client with a concrete settings
|
90
|
+
cat_client = CatClient.new domain: "awesome-cats",
|
91
|
+
user: "cat_lover",
|
127
92
|
password: "purr"
|
128
93
|
|
129
|
-
# Use low-level DSL to send requests
|
130
|
-
cat_client.
|
131
|
-
|
132
|
-
|
133
|
-
color: "tabby"
|
94
|
+
# Use verbose low-level DSL to send requests
|
95
|
+
cat_client.scopes[:cats].new(version: 2)
|
96
|
+
.operations[:update].new(id: 4, age: 10, color: "tabby")
|
97
|
+
.call # sends request
|
134
98
|
|
135
99
|
# Use top-level DSL for the same request
|
136
|
-
cat_client.cats
|
100
|
+
cat_client.cats(version: 2).update(id: 4, age: 10, color: "tabby")
|
137
101
|
|
138
|
-
# Both the methods send `PATCH https://
|
102
|
+
# Both the methods send `PATCH https://awesome-cats.example.com/api/v2/cats/4`
|
139
103
|
# with a specified body and headers (authorization via basic_auth)
|
140
104
|
```
|
141
105
|
|
@@ -145,11 +109,13 @@ The gem is available as open source under the terms of the [MIT License](http://
|
|
145
109
|
|
146
110
|
[codeclimate-badger]: https://img.shields.io/codeclimate/github/evilmartians/evil-client.svg?style=flat
|
147
111
|
[codeclimate]: https://codeclimate.com/github/evilmartians/evil-client
|
112
|
+
[dry-initializer]: http://dry-rb.org/gems/dry-initializer
|
148
113
|
[gem-badger]: https://img.shields.io/gem/v/evil-client.svg?style=flat
|
149
114
|
[gem]: https://rubygems.org/gems/evil-client
|
150
115
|
[gemnasium-badger]: https://img.shields.io/gemnasium/evilmartians/evil-client.svg?style=flat
|
151
116
|
[gemnasium]: https://gemnasium.com/evilmartians/evil-client
|
152
117
|
[inch-badger]: http://inch-ci.org/github/evilmartians/evil-client.svg
|
153
118
|
[inch]: https://inch-ci.org/github/evilmartians/evil-client
|
119
|
+
[swagger]: http://swagger.io
|
154
120
|
[travis-badger]: https://img.shields.io/travis/evilmartians/evil-client/master.svg?style=flat
|
155
121
|
[travis]: https://travis-ci.org/evilmartians/evil-client
|