evil-client 0.3.3 → 1.0.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/.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]:
|