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
data/docs/base_url.md
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
Use `base_url` to define a base url, [operation paths][path] are relative to.
|
2
|
-
|
3
|
-
You can use [`settings`][settings] as the only argument of the declaration block.
|
4
|
-
|
5
|
-
```ruby
|
6
|
-
require "evil-client"
|
7
|
-
require "dry-types"
|
8
|
-
|
9
|
-
class CatsClient < Evil::Client
|
10
|
-
settings do
|
11
|
-
option :version, type: Dry::Types["coercible.int"], default: proc { 1 }
|
12
|
-
end
|
13
|
-
|
14
|
-
base_url do |settings|
|
15
|
-
"https://cats.example.com/v#{settings.version}"
|
16
|
-
end
|
17
|
-
|
18
|
-
operation :find_cats do |_settings|
|
19
|
-
http_method :get
|
20
|
-
path { "cats" }
|
21
|
-
end
|
22
|
-
end
|
23
|
-
```
|
24
|
-
|
25
|
-
After a client's instantiation...
|
26
|
-
|
27
|
-
```ruby
|
28
|
-
client = CatsClient.new version: 3
|
29
|
-
```
|
30
|
-
|
31
|
-
...the following call will send a request `GET https://example.com/v3/cats`.
|
32
|
-
|
33
|
-
```ruby
|
34
|
-
client.operations[:find_cat].call
|
35
|
-
```
|
36
|
-
|
37
|
-
[settings]:
|
38
|
-
[path]:
|
data/docs/documentation.md
DELETED
@@ -1,9 +0,0 @@
|
|
1
|
-
Use the `documentation` to provide reference to online docs for the current operation.
|
2
|
-
|
3
|
-
```ruby
|
4
|
-
operation :find_cat do |settings| # remember that you have access to settings
|
5
|
-
documentation "https://cats.example.com/v#{settings.version}/docs/find_cats"
|
6
|
-
end
|
7
|
-
```
|
8
|
-
|
9
|
-
The link will be shown in exceptions risen when either request or response mismatches type constraints.
|
data/docs/headers.md
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
Use method `headers` to add several headers to a request. The declaration should have a block with several `attributes` describing corresponding headers.
|
2
|
-
|
3
|
-
```ruby
|
4
|
-
operation :find_cat do |settings|
|
5
|
-
headers do
|
6
|
-
attribute :token if settings.version > 1
|
7
|
-
attribute :id
|
8
|
-
end
|
9
|
-
end
|
10
|
-
```
|
11
|
-
|
12
|
-
The syntax of the attribute declaration is exactly the same as of [Evil::Struct][model]. Type constraints and default values are available.
|
13
|
-
|
14
|
-
All values for the headers will be taken from a request options:
|
15
|
-
|
16
|
-
```ruby
|
17
|
-
# Sends a request with headers { "id" => 43 }
|
18
|
-
client.options[:find_cat].call id: 43
|
19
|
-
```
|
20
|
-
|
21
|
-
As a rule, you shouldn't define authorization headers in this way. Use [the security method][security] instead.
|
22
|
-
|
23
|
-
Default headers can be declared for every request via anonymous operation. **Notice** that a default headers can be reloaded for specific operation as a whole. New declaration will overwrite all the default set headers instead of merging to them.
|
24
|
-
|
25
|
-
```ruby
|
26
|
-
operation do
|
27
|
-
headers do
|
28
|
-
attribute :id
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
operation :find_cat do
|
33
|
-
headers do
|
34
|
-
attribute :cat_id
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
# later at the runtime the following call
|
39
|
-
# will send request with { "cat_id" => 4 } header only
|
40
|
-
client.operations[:find_cat].call id: 1, cat_id: 4
|
41
|
-
```
|
42
|
-
|
43
|
-
According to [RFC-2616][rfc-2616], headers are case-insensitive. Inside [middleware][middleware] they are forced to lower case.
|
44
|
-
|
45
|
-
For example, while the following declaration is valid by itself, only value from `Foo` option will be sent to remote server:
|
46
|
-
|
47
|
-
```ruby
|
48
|
-
operation do
|
49
|
-
headers do
|
50
|
-
attribute :foo
|
51
|
-
attribute :Foo
|
52
|
-
end
|
53
|
-
end
|
54
|
-
```
|
55
|
-
|
56
|
-
[rfc-2616]: https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2
|
57
|
-
[security]:
|
58
|
-
[model]:
|
59
|
-
[middleware]:
|
data/docs/http_method.md
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
Use `http_method` to define it for the current operation.
|
2
|
-
|
3
|
-
```ruby
|
4
|
-
operation :find_cat do
|
5
|
-
http_method :get
|
6
|
-
end
|
7
|
-
```
|
8
|
-
|
9
|
-
As usual, you have access to current settings. This can be useful to make the method dependent from either a version, or other variation of the api.
|
10
|
-
|
11
|
-
```ruby
|
12
|
-
operation :find_cat do |settings|
|
13
|
-
http_method settings.version > 2 ? :post : :get
|
14
|
-
end
|
15
|
-
```
|
16
|
-
|
17
|
-
You can also set a default method for all operations. It can be reloaded later:
|
18
|
-
|
19
|
-
```ruby
|
20
|
-
operation do
|
21
|
-
http_method :get
|
22
|
-
end
|
23
|
-
|
24
|
-
operation :find_cat do
|
25
|
-
# sends requests via get
|
26
|
-
end
|
27
|
-
|
28
|
-
operation :update_cat do
|
29
|
-
http_method :patch
|
30
|
-
end
|
31
|
-
```
|
data/docs/model.md
DELETED
@@ -1,173 +0,0 @@
|
|
1
|
-
Models are simple nested structures, based on [dry-initializer][dry-initializer] and [dry-types][dry-types].
|
2
|
-
|
3
|
-
They are needed to prepare and validate nested bodies and queries, as well as wrap and validate responses.
|
4
|
-
|
5
|
-
# Model Definition
|
6
|
-
|
7
|
-
To define a model create a subclass of `Evil::Struct` and define its attributes.
|
8
|
-
|
9
|
-
```ruby
|
10
|
-
class Cat < Evil::Struct
|
11
|
-
attribute :name, type: Dry::Types["strict.string"], optional: true
|
12
|
-
attribute :age, type: Dry::Types["coercible.int"], default: proc { 0 }
|
13
|
-
attribute :color, type: Dry::Types["strict.string"]
|
14
|
-
end
|
15
|
-
```
|
16
|
-
|
17
|
-
The method `attribute` is just an alias of [dry-initializer `option`][dry-initializer]. Because model's constructor takes options only, not params, `param` is reloaded as another alias of `option`. You can use any method you like.
|
18
|
-
|
19
|
-
To initialize an instance send a hash of options to the constructor:
|
20
|
-
|
21
|
-
```ruby
|
22
|
-
cat = Cat.new(name: "Navuxodonosor II", age: "15", color: "black")
|
23
|
-
cat.name # => "Navuxodonosor II"
|
24
|
-
cat.age # => 15
|
25
|
-
cat.color # => "black"
|
26
|
-
```
|
27
|
-
|
28
|
-
You can build a model from another one (it just returns the object back):
|
29
|
-
|
30
|
-
```ruby
|
31
|
-
Cat.new Cat.new(name: "Navuxodonosor II", age: 15, color: "black")
|
32
|
-
```
|
33
|
-
|
34
|
-
or from a hash with string keys:
|
35
|
-
|
36
|
-
```ruby
|
37
|
-
Cat.new("name" => "Navuxodonosor II", "age" => 15, "color" => "black")
|
38
|
-
```
|
39
|
-
|
40
|
-
You can use other (nested) models in type definitions:
|
41
|
-
|
42
|
-
```ruby
|
43
|
-
class CatPack < Evil::Struct
|
44
|
-
attribute :cats, type: Dry::Types["array"].member(Cat)
|
45
|
-
end
|
46
|
-
|
47
|
-
CatPack.new cats: [{ name: "Navuxodonosor II", age: 15, color: "black" }]
|
48
|
-
```
|
49
|
-
|
50
|
-
Models can be converted back to hashes with **symbolic** keys:
|
51
|
-
|
52
|
-
```ruby
|
53
|
-
cat = Cat.new(name: "Navuxodonosor II", age: "15", color: "black")
|
54
|
-
cat.to_h # => { name: "Navuxodonosor II", age: "15", color: "black" }
|
55
|
-
```
|
56
|
-
|
57
|
-
The model ignores all options it doesn't know about, and applies constraints to known ones only.
|
58
|
-
|
59
|
-
```ruby
|
60
|
-
# Cats don't care about your expectations
|
61
|
-
cat = Cat.new(name: "Navuxodonosor II", age: "15", color: "black", expectation: "hunting")
|
62
|
-
cat.to_h # => { name: "Navuxodonosor II", age: "15", color: "black" }
|
63
|
-
```
|
64
|
-
|
65
|
-
If all you need is data filtering, just use a shortcut `.[]`:
|
66
|
-
|
67
|
-
```ruby
|
68
|
-
Cat[name: "Navuxodonosor II", age: "15", color: "black", expectation: "hunting"]
|
69
|
-
# => { name: "Navuxodonosor II", age: "15", color: "black" }
|
70
|
-
```
|
71
|
-
|
72
|
-
# Model Usage
|
73
|
-
|
74
|
-
You can use models in definitions of request [body][body], [query][query], and [headers][headers]...
|
75
|
-
|
76
|
-
```ruby
|
77
|
-
operation :create_cat do
|
78
|
-
method :post
|
79
|
-
path { "cats" }
|
80
|
-
body model: Cat
|
81
|
-
end
|
82
|
-
```
|
83
|
-
|
84
|
-
...and in [response][response] processing:
|
85
|
-
|
86
|
-
```ruby
|
87
|
-
operation :create_cat do
|
88
|
-
# ...
|
89
|
-
response 201 do |body:, **|
|
90
|
-
Cat[JSON.parse(body)]
|
91
|
-
end
|
92
|
-
end
|
93
|
-
```
|
94
|
-
|
95
|
-
# Distinction of Models from Dry::Struct
|
96
|
-
|
97
|
-
Models are like ~~onions~~ structures, defined in [`dry-struct`][dry-struct]. Both models and structures support hash arguments, type constraints, nested data, and backward hashification via `to_h`. You can check [dry-struct documentation] to make an impression of how it works.
|
98
|
-
|
99
|
-
Nethertheless, there is an important difference between the implementations of nested structures.
|
100
|
-
|
101
|
-
## Undefined Values vs nils
|
102
|
-
|
103
|
-
The main reason to define gem-specific model is the following. In `Dry::Struct` both the `optional` and `default` properties belong to value type constraint. The gem does not draw the line between attributes that are not set, and those that are set to `nil`.
|
104
|
-
|
105
|
-
To the contrary, in [dry-initializer][dry-initializer] and `Evil::Struct` both `optional` and `default` properties describe not a value type by itself, but its relation to the model. An attribute value can be set to `nil`, or been kept in undefined state.
|
106
|
-
|
107
|
-
Let's see the difference on the example of `StructCat` and `ModelCat`:
|
108
|
-
|
109
|
-
```ruby
|
110
|
-
class StructCat < Dry::Struct
|
111
|
-
attribute :name, type: Dry::Types["strict.string"].optional
|
112
|
-
attribute :age, type: Dry::Types["coercible.int"].default(0)
|
113
|
-
end
|
114
|
-
|
115
|
-
class ModelCat < Evil::Struct
|
116
|
-
attribute :name, type: Dry::Types["strict.string"], optional: true
|
117
|
-
attribute :age, type: Dry::Types["coercible.int"], default: proc { 0 }
|
118
|
-
end
|
119
|
-
|
120
|
-
struct_cat = StructCat.new
|
121
|
-
struct_cat.name # => nil
|
122
|
-
struct_cat.age # => 0
|
123
|
-
struct_cat.to_h # => { name: nil, age: 0 }
|
124
|
-
|
125
|
-
model_cat = ModelCat.new
|
126
|
-
model_cat.name # => #<Dry::Initializer::UNDEFINED>
|
127
|
-
model_cat.age # => 0
|
128
|
-
model_cat.to_h # => { age: 0 }
|
129
|
-
|
130
|
-
model_cat = ModelCat.new name: nil
|
131
|
-
model_cat.name # => nil
|
132
|
-
model_cat.age # => 0
|
133
|
-
model_cat.to_h # => { name: nil, age: 0 }
|
134
|
-
```
|
135
|
-
|
136
|
-
Notice that in a model hashification ignores undefined attributes. This is important to filter arguments of a request. In PUT/PATCH requests (update server-side data) there is a difference between values not changed, and those that are explicitly reset to `nil`.
|
137
|
-
|
138
|
-
## Tolerance to Unknown Options
|
139
|
-
|
140
|
-
A model's constructor ignores unknown options, so you can safely sent any ones:
|
141
|
-
|
142
|
-
```ruby
|
143
|
-
# Oh, no, this is a cat, not a bat!
|
144
|
-
model_cat = ModelCat.new name: "Abraham", flying_distance: "5 miles"
|
145
|
-
|
146
|
-
# so we simply ignore flying_distance
|
147
|
-
model_cat.to_h # => { name: "Abraham", age: 0 }
|
148
|
-
```
|
149
|
-
|
150
|
-
This behaviour allows us to slice only necessary arguments for [body][body], [query][query], and [headers][headers] of a request.
|
151
|
-
|
152
|
-
## Stringified Keys in Constructor
|
153
|
-
|
154
|
-
Ahother difference between structs and models is that models can take hashes with both symbolic and string keys.
|
155
|
-
|
156
|
-
This addition is useful when processing [responses][response]:
|
157
|
-
|
158
|
-
```ruby
|
159
|
-
# This works even though JSON#parse returns a hash with string keys
|
160
|
-
ModelCat.new JSON.parse('{"age":4}')
|
161
|
-
```
|
162
|
-
|
163
|
-
## Equality
|
164
|
-
|
165
|
-
Models, whose methods `to_h` returns equal hashes, are counted as equal.
|
166
|
-
|
167
|
-
[dry-initializer]: http://dry-rb.org/gems/dry-initializer
|
168
|
-
[dry-struct]: http://dry-rb.org/gems/dry-struct
|
169
|
-
[dry-types]: http://dry-rb.org/gems/dry-types
|
170
|
-
[body]:
|
171
|
-
[headers]:
|
172
|
-
[query]:
|
173
|
-
[response]:
|
data/docs/operation.md
DELETED
File without changes
|
data/docs/overview.md
DELETED
File without changes
|
data/docs/path.md
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
Use `path` to define operation's path that is relative to the [base url][base_url].
|
2
|
-
|
3
|
-
```ruby
|
4
|
-
operation :find_cats do
|
5
|
-
path { "cats" }
|
6
|
-
end
|
7
|
-
```
|
8
|
-
|
9
|
-
Notice that a value should be wrapped into the block. This is necessary to build paths dependent on arguments of the request. The following definition inserts a mandatory id from options:
|
10
|
-
|
11
|
-
```ruby
|
12
|
-
operation :find_cat do
|
13
|
-
path { |id:, **| "cats/#{id}" }
|
14
|
-
end
|
15
|
-
|
16
|
-
# later at a runtime
|
17
|
-
client.operations[:find_cat].call id: 98 # sends to "/cats/98"
|
18
|
-
```
|
19
|
-
|
20
|
-
As usual, you have access to current settings. This can be useful to add client tokens to paths when necessary:
|
21
|
-
|
22
|
-
```ruby
|
23
|
-
operation :find_cats do |settings|
|
24
|
-
path { "cats/#{settings.token}" }
|
25
|
-
end
|
26
|
-
```
|
27
|
-
|
28
|
-
## Default Path
|
29
|
-
|
30
|
-
You can set a default path for all operations. Use it to DRY clients whose operations differs not by endpoints, but, for example, by parameters ([query][query], [body][body]) of various requests:
|
31
|
-
|
32
|
-
```ruby
|
33
|
-
operation do
|
34
|
-
path { "cats" }
|
35
|
-
end
|
36
|
-
|
37
|
-
operation :find_cats do
|
38
|
-
# sends requests to "/cats"
|
39
|
-
end
|
40
|
-
|
41
|
-
operation :find_details do
|
42
|
-
path { "cats/details" } # reloads default setting
|
43
|
-
end
|
44
|
-
```
|
45
|
-
|
46
|
-
[base_url]:
|
47
|
-
[query]:
|
48
|
-
[body]:
|
data/docs/query.md
DELETED
@@ -1,99 +0,0 @@
|
|
1
|
-
Use `query` to add some data to the request query. The syntax is pretty the same as for [body][body] and [headers][headers].
|
2
|
-
|
3
|
-
```ruby
|
4
|
-
operation :find_cat do |settings|
|
5
|
-
# ...
|
6
|
-
path { "cats" }
|
7
|
-
query do
|
8
|
-
attribute :token, default: proc { settings.token }
|
9
|
-
attribute :id
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
# Later at the runtime it will send a request to "../cats?id=4&token=foo"
|
14
|
-
client.operations[:find_cat].call id: 4, token: "foo"
|
15
|
-
```
|
16
|
-
|
17
|
-
## Nested Data Representation
|
18
|
-
|
19
|
-
Nested data are represented in a query following Rails convention:
|
20
|
-
|
21
|
-
```ruby
|
22
|
-
client.operations[:find_cat].call id: [{ key: 4 }], token: ["foo"]
|
23
|
-
# "/cats?id[][key]=4&token[]=foo"
|
24
|
-
```
|
25
|
-
|
26
|
-
Non-unicode symbols are encoded as defined in [RFC-3986][rfc-3986]
|
27
|
-
|
28
|
-
## Model-Based Queries
|
29
|
-
|
30
|
-
Use [models][model] to provide validation of query data:
|
31
|
-
|
32
|
-
```ruby
|
33
|
-
class Cat < Evil::Struct
|
34
|
-
attribute :name, type: Dry::Types["strict.string"], optional: true
|
35
|
-
attribute :age, type: Dry::Types["strict.int"], default: proc { 0 }
|
36
|
-
attribute :color, type: Dry::Types["strict.string"]
|
37
|
-
end
|
38
|
-
```
|
39
|
-
|
40
|
-
You can either restrict `type` of an attribute:
|
41
|
-
|
42
|
-
```ruby
|
43
|
-
operation :create_cat do
|
44
|
-
query do
|
45
|
-
attribute :cat, type: Cat
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
# Later at runtime will send "...?cat[color]=tabby&cat[age]=0"
|
50
|
-
client.operations[:create_cat].call cat: { color: "tabby" }
|
51
|
-
```
|
52
|
-
|
53
|
-
...or use in for the query as a whole under the `model` key:
|
54
|
-
|
55
|
-
```ruby
|
56
|
-
operation :create_cat do
|
57
|
-
query model: Cat
|
58
|
-
end
|
59
|
-
|
60
|
-
# Later at runtime will send "...?color=tabby&age=0"
|
61
|
-
client.operations[:create_cat].call color: "tabby"
|
62
|
-
```
|
63
|
-
|
64
|
-
In the last case you can define additional attributes (this redefinition is local, it don't affect a model by itself):
|
65
|
-
|
66
|
-
```ruby
|
67
|
-
operation :create_cat do
|
68
|
-
query model: Cat do
|
69
|
-
attribute :mood, default: proc { "sleeping" }
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
# Later at runtime will send "...?color=tabby&age=0&mood=sleeping"
|
74
|
-
client.operations[:create_cat].call color: "tabby"
|
75
|
-
```
|
76
|
-
|
77
|
-
**Be careful!** You cannot reload existing attributes (this will cause an exception).
|
78
|
-
|
79
|
-
In operations that update remote data you can skip some attributes (mark them `optional`). If you need to check responses strictly (to require all the necessary attributes), you should provide different models.
|
80
|
-
|
81
|
-
```ruby
|
82
|
-
# Requires remote server to return consistent beasts
|
83
|
-
class Cat
|
84
|
-
attribute :id, type: Dry::Types["strict.int"].constrained(gt: 0)
|
85
|
-
attribute :age, type: Dry::Types["strict.int"]
|
86
|
-
attribute :name, type: Dry::Types["strict.string"]
|
87
|
-
end
|
88
|
-
|
89
|
-
# Allows updating attributes when necessary
|
90
|
-
class CatUpdate
|
91
|
-
attribute :age, type: Dry::Types["coercible.int"], optional: true
|
92
|
-
attribute :name, type: Dry::Types["coercible.string"], optional: true
|
93
|
-
end
|
94
|
-
```
|
95
|
-
|
96
|
-
[rfc-3986]: https://tools.ietf.org/html/rfc3986
|
97
|
-
[body]:
|
98
|
-
[headers]:
|
99
|
-
[model]:
|