dry-swagger 0.7.2 → 2.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/.github/workflows/main.yml +27 -0
- data/.gitignore +2 -2
- data/CODE_OF_CONDUCT.md +1 -1
- data/Gemfile +2 -2
- data/Gemfile.lock +44 -35
- data/LICENSE.txt +1 -1
- data/README.md +126 -240
- data/dry-swagger.gemspec +3 -0
- data/lib/dry/swagger/config/{struct_configuration.rb → swagger_configuration.rb} +1 -1
- data/lib/dry/swagger/documentation_generator.rb +12 -4
- data/lib/dry/swagger/tasks/configuration_generator.rake +3 -10
- data/lib/dry/swagger/version.rb +1 -1
- data/lib/dry/swagger.rb +1 -4
- metadata +34 -9
- data/.travis.yml +0 -6
- data/lib/dry/swagger/config/contract_configuration.rb +0 -15
- data/lib/dry/swagger/contract_parser.rb +0 -128
- data/lib/dry/swagger/struct_parser.rb +0 -144
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e9f90c08a2cc2e78fca981c2e4db7836cb1f14632b478d6bb951146cb9101d66
|
4
|
+
data.tar.gz: 33bf560f05ecac510ff401ebe3067e487ee28b7378395a0f97b3a44f6a4388a7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 93d02007263ab18d0f37f7e41013eeb75082ceaec296f8023d104f6cbf5ea15874a6130cb89b0bfe5af5dbc602104948b41d2bc4ce929397535210e3d9e63158
|
7
|
+
data.tar.gz: 80436b836812d8550c7798506e585ba7368f61db3afa08fae34c3ae7eeb940b24dedcab2e297176140d060a4841d8f4716d9ea3add070fbdbac90f7b51efebec
|
@@ -0,0 +1,27 @@
|
|
1
|
+
name: Ruby
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- master
|
7
|
+
|
8
|
+
pull_request:
|
9
|
+
|
10
|
+
jobs:
|
11
|
+
build:
|
12
|
+
runs-on: ubuntu-latest
|
13
|
+
name: Ruby ${{ matrix.ruby }}
|
14
|
+
strategy:
|
15
|
+
matrix:
|
16
|
+
ruby:
|
17
|
+
- '3.2.2'
|
18
|
+
|
19
|
+
steps:
|
20
|
+
- uses: actions/checkout@v4
|
21
|
+
- name: Set up Ruby
|
22
|
+
uses: ruby/setup-ruby@v1
|
23
|
+
with:
|
24
|
+
ruby-version: ${{ matrix.ruby }}
|
25
|
+
bundler-cache: true
|
26
|
+
- name: Run Tests
|
27
|
+
run: bundle exec rspec
|
data/.gitignore
CHANGED
data/CODE_OF_CONDUCT.md
CHANGED
@@ -55,7 +55,7 @@ further defined and clarified by project maintainers.
|
|
55
55
|
## Enforcement
|
56
56
|
|
57
57
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
-
reported by contacting the project team at
|
58
|
+
reported by contacting the project team at janeterziev@gmail.com. All
|
59
59
|
complaints will be reviewed and investigated and will result in a response that
|
60
60
|
is deemed necessary and appropriate to the circumstances. The project team is
|
61
61
|
obligated to maintain confidentiality with regard to the reporter of an incident.
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,51 +1,59 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
dry-swagger (0.
|
4
|
+
dry-swagger (2.0.0)
|
5
|
+
dry_struct_parser
|
6
|
+
dry_validation_parser
|
5
7
|
|
6
8
|
GEM
|
7
9
|
remote: https://rubygems.org/
|
8
10
|
specs:
|
9
|
-
|
11
|
+
bigdecimal (3.1.5)
|
12
|
+
concurrent-ruby (1.2.2)
|
10
13
|
diff-lcs (1.4.4)
|
11
|
-
dry-configurable (
|
14
|
+
dry-configurable (1.1.0)
|
15
|
+
dry-core (~> 1.0, < 2)
|
16
|
+
zeitwerk (~> 2.6)
|
17
|
+
dry-core (1.0.1)
|
12
18
|
concurrent-ruby (~> 1.0)
|
13
|
-
|
14
|
-
dry-
|
19
|
+
zeitwerk (~> 2.6)
|
20
|
+
dry-inflector (1.0.0)
|
21
|
+
dry-initializer (3.1.1)
|
22
|
+
dry-logic (1.5.0)
|
15
23
|
concurrent-ruby (~> 1.0)
|
16
|
-
dry-
|
17
|
-
|
24
|
+
dry-core (~> 1.0, < 2)
|
25
|
+
zeitwerk (~> 2.6)
|
26
|
+
dry-schema (1.13.3)
|
18
27
|
concurrent-ruby (~> 1.0)
|
19
|
-
|
20
|
-
|
21
|
-
dry-initializer (3.0.4)
|
22
|
-
dry-logic (1.2.0)
|
23
|
-
concurrent-ruby (~> 1.0)
|
24
|
-
dry-core (~> 0.5, >= 0.5)
|
25
|
-
dry-schema (1.7.0)
|
26
|
-
concurrent-ruby (~> 1.0)
|
27
|
-
dry-configurable (~> 0.8, >= 0.8.3)
|
28
|
-
dry-core (~> 0.5, >= 0.5)
|
28
|
+
dry-configurable (~> 1.0, >= 1.0.1)
|
29
|
+
dry-core (~> 1.0, < 2)
|
29
30
|
dry-initializer (~> 3.0)
|
30
|
-
dry-logic (
|
31
|
-
dry-types (
|
32
|
-
|
33
|
-
|
34
|
-
dry-
|
31
|
+
dry-logic (>= 1.4, < 2)
|
32
|
+
dry-types (>= 1.7, < 2)
|
33
|
+
zeitwerk (~> 2.6)
|
34
|
+
dry-struct (1.6.0)
|
35
|
+
dry-core (~> 1.0, < 2)
|
36
|
+
dry-types (>= 1.7, < 2)
|
35
37
|
ice_nine (~> 0.11)
|
36
|
-
|
38
|
+
zeitwerk (~> 2.6)
|
39
|
+
dry-types (1.7.2)
|
40
|
+
bigdecimal (~> 3.0)
|
37
41
|
concurrent-ruby (~> 1.0)
|
38
|
-
dry-
|
39
|
-
dry-
|
40
|
-
dry-
|
41
|
-
|
42
|
-
dry-validation (1.
|
42
|
+
dry-core (~> 1.0)
|
43
|
+
dry-inflector (~> 1.0)
|
44
|
+
dry-logic (~> 1.4)
|
45
|
+
zeitwerk (~> 2.6)
|
46
|
+
dry-validation (1.10.0)
|
43
47
|
concurrent-ruby (~> 1.0)
|
44
|
-
dry-
|
45
|
-
dry-core (~> 0.4)
|
46
|
-
dry-equalizer (~> 0.2)
|
48
|
+
dry-core (~> 1.0, < 2)
|
47
49
|
dry-initializer (~> 3.0)
|
48
|
-
dry-schema (
|
50
|
+
dry-schema (>= 1.12, < 2)
|
51
|
+
zeitwerk (~> 2.6)
|
52
|
+
dry_struct_parser (0.1.0)
|
53
|
+
dry-struct (~> 1)
|
54
|
+
dry_validation_parser (0.1.7)
|
55
|
+
dry-types (~> 1)
|
56
|
+
dry-validation (~> 1)
|
49
57
|
i18n (1.8.10)
|
50
58
|
concurrent-ruby (~> 1.0)
|
51
59
|
ice_nine (0.11.2)
|
@@ -63,17 +71,18 @@ GEM
|
|
63
71
|
diff-lcs (>= 1.2.0, < 2.0)
|
64
72
|
rspec-support (~> 3.10.0)
|
65
73
|
rspec-support (3.10.2)
|
74
|
+
zeitwerk (2.6.12)
|
66
75
|
|
67
76
|
PLATFORMS
|
68
77
|
ruby
|
69
78
|
|
70
79
|
DEPENDENCIES
|
71
|
-
dry-struct
|
72
80
|
dry-swagger!
|
73
|
-
|
81
|
+
dry_struct_parser
|
82
|
+
dry_validation_parser
|
74
83
|
i18n
|
75
84
|
rake (~> 12.0)
|
76
85
|
rspec (~> 3.0)
|
77
86
|
|
78
87
|
BUNDLED WITH
|
79
|
-
2.
|
88
|
+
2.5.4
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -3,6 +3,25 @@
|
|
3
3
|
Generate a valid and up to date swagger documentation out of your dry-structs and dry-validations
|
4
4
|
|
5
5
|
The gem is still work in progress and is not yet fully tested.
|
6
|
+
## IMPORTANT:
|
7
|
+
|
8
|
+
If you are upgrading from version 1 to version 2, you will need to replace:
|
9
|
+
|
10
|
+
Dry::Swagger::StructParser.new.call(struct)
|
11
|
+
with
|
12
|
+
|
13
|
+
Dry::Swagger::DocumentationGenerator.new.from_struct(struct)
|
14
|
+
and replace
|
15
|
+
|
16
|
+
Dry::Swagger::ContractParser.new.call(contract)
|
17
|
+
with
|
18
|
+
|
19
|
+
Dry::Swagger::DocumentationGenerator.new.from_validation(contract).
|
20
|
+
|
21
|
+
For the configuration file in project/config/initializers/dry-swagger.rb, you will need to replace:
|
22
|
+
|
23
|
+
Dry::Swagger::Config::ContractConfiguration -> Dry::Swagger::Config::SwaggerConfiguration
|
24
|
+
you do not need both ContractConfiguration and StructConfiguration.
|
6
25
|
## Installation
|
7
26
|
|
8
27
|
Add this line to your application's Gemfile:
|
@@ -21,11 +40,9 @@ After installing, execute the following command:
|
|
21
40
|
|
22
41
|
This will generate configuration files in your project under `project/config`. See Configuration section for more details.
|
23
42
|
|
24
|
-
##Usage
|
43
|
+
## Usage
|
25
44
|
|
26
|
-
####With Dry::Validation::Contract
|
27
|
-
Lets say we have the following Dry::Validation::Contract definition:
|
28
|
-
|
45
|
+
#### With Dry::Validation::Contract
|
29
46
|
class TestContract < Dry::Validation::Contract
|
30
47
|
params do
|
31
48
|
required(:some_field).value(:str?, min_size?: 5, max_size?: 10)
|
@@ -39,128 +56,63 @@ Lets say we have the following Dry::Validation::Contract definition:
|
|
39
56
|
end
|
40
57
|
end
|
41
58
|
|
42
|
-
|
43
|
-
|
44
|
-
`parser.call(TestContract)` will set the `keys` of the `parser` object to:
|
45
|
-
|
46
|
-
{
|
47
|
-
:some_field => {
|
48
|
-
:required => true,
|
49
|
-
:type => "string",
|
50
|
-
:description => "Minimum size: 5, Maximum size: 10"
|
51
|
-
},
|
52
|
-
:some_array_of_objects => {
|
53
|
-
:required => true,
|
54
|
-
:array => true,
|
55
|
-
:type => "array",
|
56
|
-
:keys => {
|
57
|
-
:some_nested_attribute => {
|
58
|
-
:required=>true, :type=>"string"
|
59
|
-
}
|
60
|
-
}
|
61
|
-
},
|
62
|
-
:some_array_of_integers => {
|
63
|
-
:required=>true,
|
64
|
-
:array=>true,
|
65
|
-
:type=>"integer"
|
66
|
-
},
|
67
|
-
:dto => {
|
68
|
-
:required => true,
|
69
|
-
:type => "hash",
|
70
|
-
:keys => {
|
71
|
-
:some_nested_attribute => {
|
72
|
-
:required => false,
|
73
|
-
:"x-nullable"=>true,
|
74
|
-
:type=>"string"
|
75
|
-
}
|
76
|
-
}
|
77
|
-
}
|
78
|
-
}
|
79
|
-
|
80
|
-
As we can see, the `ContractParser` goes through all the params defined in the
|
81
|
-
schema and generates a hash. The hash is saved in the `keys` attribute of the parser,
|
82
|
-
so that we can call `to_swagger` later.
|
83
|
-
|
84
|
-
The required key in our result will be set to `true` if the field is defined as
|
85
|
-
`required(:field_name)`, and `false` if defined as `optional(:field_name)`.
|
86
|
-
|
87
|
-
The "x-nullable" key depends on whether we have defined the field as value, maybe or filled.
|
88
|
-
|
89
|
-
For nested objects like array of objects or hash, we add a keys field with a definition
|
90
|
-
for each field inside the nested hash.
|
91
|
-
|
92
|
-
If the field is an array of primitive type, the type field will equal to the primitive type, and a
|
93
|
-
array flag will be set on the field.
|
94
|
-
|
95
|
-
Calling `parser.to_swagger` will give the following result:
|
96
|
-
|
97
|
-
{
|
98
|
-
"type": "object",
|
99
|
-
"properties": {
|
100
|
-
"some_field": {
|
101
|
-
"type": "string",
|
102
|
-
"description": "Minimum size: 5, Maximum size: 10",
|
103
|
-
"x-nullable": false
|
104
|
-
},
|
105
|
-
"some_array_of_objects": {
|
106
|
-
"type": "array",
|
107
|
-
"items": {
|
108
|
-
"type": "object",
|
109
|
-
"properties": {
|
110
|
-
"some_nested_attribute": {
|
111
|
-
"type": "string",
|
112
|
-
"x-nullable": false
|
113
|
-
}
|
114
|
-
},
|
115
|
-
"required": [
|
116
|
-
"some_nested_attribute"
|
117
|
-
],
|
118
|
-
"x-nullable": false
|
119
|
-
},
|
120
|
-
"x-nullable": false
|
121
|
-
},
|
122
|
-
"some_array_of_integers": {
|
123
|
-
"type": "array",
|
124
|
-
"items": {
|
125
|
-
"type": "integer",
|
126
|
-
"x-nullable": false
|
127
|
-
},
|
128
|
-
"x-nullable": false
|
129
|
-
},
|
130
|
-
"dto": {
|
59
|
+
Dry::Swagger::DocumentationGenerator.new.from_validation(TestContract)
|
60
|
+
=> {
|
131
61
|
"type": "object",
|
132
62
|
"properties": {
|
133
|
-
"
|
63
|
+
"some_field": {
|
134
64
|
"type": "string",
|
135
|
-
"
|
65
|
+
"description": "Minimum size: 5, Maximum size: 10",
|
66
|
+
"x-nullable": false
|
67
|
+
},
|
68
|
+
"some_array_of_objects": {
|
69
|
+
"type": "array",
|
70
|
+
"items": {
|
71
|
+
"type": "object",
|
72
|
+
"properties": {
|
73
|
+
"some_nested_attribute": {
|
74
|
+
"type": "string",
|
75
|
+
"x-nullable": false
|
76
|
+
}
|
77
|
+
},
|
78
|
+
"required": [
|
79
|
+
"some_nested_attribute"
|
80
|
+
],
|
81
|
+
"x-nullable": false
|
82
|
+
},
|
83
|
+
"x-nullable": false
|
84
|
+
},
|
85
|
+
"some_array_of_integers": {
|
86
|
+
"type": "array",
|
87
|
+
"items": {
|
88
|
+
"type": "integer",
|
89
|
+
"x-nullable": false
|
90
|
+
},
|
91
|
+
"x-nullable": false
|
92
|
+
},
|
93
|
+
"dto": {
|
94
|
+
"type": "object",
|
95
|
+
"properties": {
|
96
|
+
"some_nested_attribute": {
|
97
|
+
"type": "string",
|
98
|
+
"x-nullable": true
|
99
|
+
}
|
100
|
+
},
|
101
|
+
"required": [
|
102
|
+
|
103
|
+
],
|
104
|
+
"x-nullable": false
|
136
105
|
}
|
137
106
|
},
|
138
107
|
"required": [
|
139
|
-
|
140
|
-
|
141
|
-
|
108
|
+
"some_field",
|
109
|
+
"some_array_of_objects",
|
110
|
+
"some_array_of_integers",
|
111
|
+
"dto"
|
112
|
+
]
|
142
113
|
}
|
143
|
-
},
|
144
|
-
"required": [
|
145
|
-
"some_field",
|
146
|
-
"some_array_of_objects",
|
147
|
-
"some_array_of_integers",
|
148
|
-
"dto"
|
149
|
-
]
|
150
|
-
}
|
151
|
-
|
152
|
-
####With Dry::Struct
|
153
|
-
The `Dry::Swagger::StructParser` works the same as the contract parser.
|
154
|
-
|
155
|
-
The required key depends on whether we define the field as attribute or attribute?
|
156
114
|
|
157
|
-
|
158
|
-
|
159
|
-
For more complex types, for example DTO1 | DTO2 or Types::Array.of(DTO1 | DTO2),
|
160
|
-
the parser converts the field value to an array of both schemas.
|
161
|
-
|
162
|
-
Example:
|
163
|
-
|
115
|
+
#### With Dry::Struct
|
164
116
|
class DTO1 < Dry::Struct
|
165
117
|
attribute :dto1_field, Types::String
|
166
118
|
end
|
@@ -172,145 +124,79 @@ Example:
|
|
172
124
|
class DTO < Dry::Struct
|
173
125
|
attribute :dynamic_dto, DTO1 | DTO2
|
174
126
|
end
|
175
|
-
parser = Dry::Swagger::StructParser.new
|
176
|
-
|
177
|
-
parser.call(DTO)
|
178
|
-
=> {
|
179
|
-
"dynamic_dto": [ # ARRAY
|
180
|
-
{
|
181
|
-
"type": "hash",
|
182
|
-
"required": true,
|
183
|
-
"x-nullable": false,
|
184
|
-
"keys": {
|
185
|
-
"dto1_field": {
|
186
|
-
"type": "string",
|
187
|
-
"required": true,
|
188
|
-
"x-nullable": false
|
189
|
-
}
|
190
|
-
}
|
191
|
-
},
|
192
|
-
{
|
193
|
-
"type": "hash",
|
194
|
-
"required": true,
|
195
|
-
"x-nullable": false,
|
196
|
-
"keys": {
|
197
|
-
"dto2_field": {
|
198
|
-
"type": "string",
|
199
|
-
"required": true,
|
200
|
-
"x-nullable": false
|
201
|
-
}
|
202
|
-
}
|
203
|
-
}
|
204
|
-
]
|
205
|
-
}
|
206
127
|
|
207
|
-
|
208
|
-
|
209
|
-
{
|
210
|
-
"type": "object",
|
211
|
-
"properties": {
|
212
|
-
"dynamic_dto": {
|
128
|
+
Dry::Swagger::DocumentationGenerator.new.from_struct(DTO)
|
129
|
+
=> {
|
213
130
|
"type": "object",
|
214
131
|
"properties": {
|
215
|
-
"
|
132
|
+
"dynamic_dto": {
|
216
133
|
"type": "object",
|
217
134
|
"properties": {
|
218
|
-
"
|
219
|
-
"type": "
|
135
|
+
"definition_1": {
|
136
|
+
"type": "object",
|
137
|
+
"properties": {
|
138
|
+
"dto1_field": {
|
139
|
+
"type": "string",
|
140
|
+
"x-nullable": false
|
141
|
+
}
|
142
|
+
},
|
143
|
+
"required": [
|
144
|
+
"dto1_field"
|
145
|
+
],
|
220
146
|
"x-nullable": false
|
221
|
-
}
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
147
|
+
},
|
148
|
+
"definition_2": {
|
149
|
+
"type": "object",
|
150
|
+
"properties": {
|
151
|
+
"dto2_field": {
|
152
|
+
"type": "string",
|
153
|
+
"x-nullable": false
|
154
|
+
}
|
155
|
+
},
|
156
|
+
"required": [
|
157
|
+
"dto2_field"
|
158
|
+
],
|
233
159
|
"x-nullable": false
|
234
160
|
}
|
235
161
|
},
|
236
|
-
"
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
162
|
+
"example": "Dynamic Field. See Model Definitions",
|
163
|
+
"oneOf": [
|
164
|
+
{
|
165
|
+
"type": "object",
|
166
|
+
"properties": {
|
167
|
+
"dto1_field": {
|
168
|
+
"type": "string",
|
169
|
+
"x-nullable": false
|
170
|
+
}
|
171
|
+
},
|
172
|
+
"required": [
|
173
|
+
"dto1_field"
|
174
|
+
],
|
249
175
|
"x-nullable": false
|
250
|
-
}
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
176
|
+
},
|
177
|
+
{
|
178
|
+
"type": "object",
|
179
|
+
"properties": {
|
180
|
+
"dto2_field": {
|
181
|
+
"type": "string",
|
182
|
+
"x-nullable": false
|
183
|
+
}
|
184
|
+
},
|
185
|
+
"required": [
|
186
|
+
"dto2_field"
|
187
|
+
],
|
262
188
|
"x-nullable": false
|
263
189
|
}
|
264
|
-
|
265
|
-
"required": [
|
266
|
-
"dto2_field"
|
267
|
-
],
|
268
|
-
"x-nullable": false
|
190
|
+
]
|
269
191
|
}
|
192
|
+
},
|
193
|
+
"required": [
|
194
|
+
"dynamic_dto"
|
270
195
|
]
|
271
196
|
}
|
272
|
-
},
|
273
|
-
"required": [
|
274
|
-
"dynamic_dto"
|
275
|
-
]
|
276
|
-
}
|
277
197
|
|
278
198
|
## Overriding fields
|
279
|
-
|
280
|
-
|
281
|
-
Dry::Swagger::StructParser.new.call(DTO) do |it|
|
282
|
-
# types = string/integer/hash/array
|
283
|
-
|
284
|
-
# Remove a field
|
285
|
-
its.keys = it.keys.except(:field_name)
|
286
|
-
|
287
|
-
# Add new field on root level
|
288
|
-
it.keys[:new_field_name] = { type: type, required: true/false, :it.config.nullable_type=>true/false }
|
289
|
-
|
290
|
-
# Add a new field in nested hash/array
|
291
|
-
it.keys[:nested_field][:keys][:new_field_name] = {
|
292
|
-
type: type, required: true/false, :it.config.nullable_type=>true/false
|
293
|
-
}
|
294
|
-
|
295
|
-
# Remove a field in nested hash/array
|
296
|
-
it.keys = it.keys[:nested_field][:keys].except(:field_name)
|
297
|
-
|
298
|
-
# Add an array or hash
|
299
|
-
it.keys[:nested_field] = {
|
300
|
-
type: "array/hash", required: true/false, :it.config.nullable_type=> true/false, keys: {
|
301
|
-
# List all nested fields
|
302
|
-
new_field: { type: :type, required: true/false, :it.config.nullable_type=>true/false }
|
303
|
-
}
|
304
|
-
}
|
305
|
-
|
306
|
-
# Add an Array of primitive types, type field needs to be the element type(string, integer, float),
|
307
|
-
and add an array: true flag
|
308
|
-
|
309
|
-
it.keys[:array_field_name] = {
|
310
|
-
type: type, array: true, required: true/false, :it.config.nullable_type=> true/false
|
311
|
-
}
|
312
|
-
|
313
|
-
end.to_swagger()
|
199
|
+
The documentation generator returns the result as a hash, so you can easily modify it based on your needs.
|
314
200
|
|
315
201
|
## Custom Configuration For Your Project
|
316
202
|
You can override default configurations by changing the values in the `config/initializers/dry-swagger.rb` file generated from the rake command in the Installation section.
|
data/dry-swagger.gemspec
CHANGED
@@ -11,8 +11,16 @@ module Dry
|
|
11
11
|
"time" => { type: :string, format: :time },
|
12
12
|
}.freeze
|
13
13
|
|
14
|
-
def initialize
|
15
|
-
@config =
|
14
|
+
def initialize
|
15
|
+
@config = Config::SwaggerConfiguration
|
16
|
+
end
|
17
|
+
|
18
|
+
def from_struct(struct)
|
19
|
+
generate_documentation(DryStructParser::StructSchemaParser.new.call(struct).keys)
|
20
|
+
end
|
21
|
+
|
22
|
+
def from_validation(validation)
|
23
|
+
generate_documentation(DryValidationParser::ValidationSchemaParser.new.call(validation).keys)
|
16
24
|
end
|
17
25
|
|
18
26
|
def generate_documentation(fields)
|
@@ -45,7 +53,7 @@ module Dry
|
|
45
53
|
documentation = generate_for_primitive_type(definition)
|
46
54
|
end
|
47
55
|
@config.enable_nullable_validation ?
|
48
|
-
documentation.merge(@config.nullable_type => definition.fetch(
|
56
|
+
documentation.merge(@config.nullable_type => definition.fetch(:nullable, false)) :
|
49
57
|
documentation.merge(@config.nullable_type => true)
|
50
58
|
|
51
59
|
rescue KeyError
|
@@ -80,7 +88,7 @@ module Dry
|
|
80
88
|
SWAGGER_FIELD_TYPE_DEFINITIONS.fetch(definition.fetch(:type)) :
|
81
89
|
generate_documentation(definition.fetch(:keys))
|
82
90
|
items = @config.enable_nullable_validation ?
|
83
|
-
items.merge(@config.nullable_type => definition.fetch(
|
91
|
+
items.merge(@config.nullable_type => definition.fetch(:nullable, false)) :
|
84
92
|
items.merge(@config.nullable_type => true)
|
85
93
|
{ type: :array, items: items }
|
86
94
|
end
|
@@ -1,26 +1,19 @@
|
|
1
1
|
require 'fileutils'
|
2
2
|
|
3
3
|
namespace 'dry-swagger' do
|
4
|
-
desc 'Create a configuration file for
|
4
|
+
desc 'Create a configuration file for Dry Swagger Documentation Generator'
|
5
5
|
task :create_configuration_file do
|
6
6
|
FileUtils.mkdir_p "#{ Dir.pwd }/config/initializers/"
|
7
7
|
puts "Created #{ Dir.pwd }/config/initializers/dry-swagger.rb"
|
8
8
|
File.open("#{ Dir.pwd }/config/initializers/dry-swagger.rb", "w") { |file|
|
9
|
-
file.puts 'Dry::Swagger::Config::
|
9
|
+
file.puts 'Dry::Swagger::Config::SwaggerConfiguration.configuration do |config|
|
10
10
|
config.enable_required_validation = true
|
11
11
|
config.enable_nullable_validation = true
|
12
12
|
config.enable_enums = true
|
13
13
|
config.enable_descriptions = true
|
14
14
|
config.nullable_type = :"x-nullable" # or :nullable
|
15
15
|
end
|
16
|
-
|
17
|
-
Dry::Swagger::Config::ContractConfiguration.configuration do |config|
|
18
|
-
config.enable_required_validation = true
|
19
|
-
config.enable_nullable_validation = true
|
20
|
-
config.enable_enums = true
|
21
|
-
config.enable_descriptions = true
|
22
|
-
config.nullable_type = :"x-nullable" # or :nullable
|
23
|
-
end'
|
16
|
+
'
|
24
17
|
}
|
25
18
|
end
|
26
19
|
|
data/lib/dry/swagger/version.rb
CHANGED
data/lib/dry/swagger.rb
CHANGED
@@ -1,12 +1,9 @@
|
|
1
1
|
require "dry/swagger/version"
|
2
|
-
require "dry/swagger/contract_parser"
|
3
|
-
require "dry/swagger/struct_parser"
|
4
2
|
require 'dry/swagger/documentation_generator'
|
5
3
|
require 'dry/swagger/errors/missing_hash_schema_error'
|
6
4
|
require 'dry/swagger/errors/missing_type_error'
|
7
5
|
require 'dry/swagger/config/configuration'
|
8
|
-
require 'dry/swagger/config/
|
9
|
-
require 'dry/swagger/config/struct_configuration'
|
6
|
+
require 'dry/swagger/config/swagger_configuration'
|
10
7
|
require 'i18n'
|
11
8
|
require 'dry/swagger/railtie' if defined?(Rails)
|
12
9
|
|
metadata
CHANGED
@@ -1,15 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dry-swagger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jane-Terziev
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
12
|
-
dependencies:
|
11
|
+
date: 2024-01-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: dry_struct_parser
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: dry_validation_parser
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
13
41
|
description: A parser which converts dry-validation or dry-struct into valid swagger
|
14
42
|
documentation
|
15
43
|
email:
|
@@ -18,10 +46,10 @@ executables: []
|
|
18
46
|
extensions: []
|
19
47
|
extra_rdoc_files: []
|
20
48
|
files:
|
49
|
+
- ".github/workflows/main.yml"
|
21
50
|
- ".gitignore"
|
22
51
|
- ".rakeTasks"
|
23
52
|
- ".rspec"
|
24
|
-
- ".travis.yml"
|
25
53
|
- CODE_OF_CONDUCT.md
|
26
54
|
- Gemfile
|
27
55
|
- Gemfile.lock
|
@@ -33,14 +61,11 @@ files:
|
|
33
61
|
- dry-swagger.gemspec
|
34
62
|
- lib/dry/swagger.rb
|
35
63
|
- lib/dry/swagger/config/configuration.rb
|
36
|
-
- lib/dry/swagger/config/
|
37
|
-
- lib/dry/swagger/config/struct_configuration.rb
|
38
|
-
- lib/dry/swagger/contract_parser.rb
|
64
|
+
- lib/dry/swagger/config/swagger_configuration.rb
|
39
65
|
- lib/dry/swagger/documentation_generator.rb
|
40
66
|
- lib/dry/swagger/errors/missing_hash_schema_error.rb
|
41
67
|
- lib/dry/swagger/errors/missing_type_error.rb
|
42
68
|
- lib/dry/swagger/railtie.rb
|
43
|
-
- lib/dry/swagger/struct_parser.rb
|
44
69
|
- lib/dry/swagger/tasks/configuration_generator.rake
|
45
70
|
- lib/dry/swagger/types.rb
|
46
71
|
- lib/dry/swagger/version.rb
|
@@ -67,7 +92,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
67
92
|
- !ruby/object:Gem::Version
|
68
93
|
version: '0'
|
69
94
|
requirements: []
|
70
|
-
rubygems_version: 3.
|
95
|
+
rubygems_version: 3.4.10
|
71
96
|
signing_key:
|
72
97
|
specification_version: 4
|
73
98
|
summary: Generate dry-validation and dry-struct into valid swagger documentation
|
data/.travis.yml
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
module Dry
|
2
|
-
module Swagger
|
3
|
-
module Config
|
4
|
-
module ContractConfiguration
|
5
|
-
extend Configuration
|
6
|
-
|
7
|
-
define_setting :enable_required_validation, true
|
8
|
-
define_setting :enable_nullable_validation, true
|
9
|
-
define_setting :enable_enums, true
|
10
|
-
define_setting :enable_descriptions, true
|
11
|
-
define_setting :nullable_type, :"x-nullable"
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,128 +0,0 @@
|
|
1
|
-
module Dry
|
2
|
-
module Swagger
|
3
|
-
class ContractParser
|
4
|
-
PREDICATE_TO_TYPE = {
|
5
|
-
array?: 'array',
|
6
|
-
bool?: 'boolean',
|
7
|
-
date?: 'date',
|
8
|
-
date_time?: 'datetime',
|
9
|
-
decimal?: 'float',
|
10
|
-
float?: 'float',
|
11
|
-
hash?: 'hash',
|
12
|
-
int?: 'integer',
|
13
|
-
nil?: 'nil',
|
14
|
-
str?: 'string',
|
15
|
-
time?: 'time'
|
16
|
-
}.freeze
|
17
|
-
|
18
|
-
# @api private
|
19
|
-
attr_reader :keys
|
20
|
-
|
21
|
-
# @api private
|
22
|
-
def initialize
|
23
|
-
@keys = {}
|
24
|
-
@config = Config::ContractConfiguration
|
25
|
-
end
|
26
|
-
|
27
|
-
# @api private
|
28
|
-
def to_h
|
29
|
-
{ keys: keys }
|
30
|
-
end
|
31
|
-
|
32
|
-
# @api private
|
33
|
-
def call(contract, &block)
|
34
|
-
@keys = {}
|
35
|
-
visit(contract.schema.to_ast)
|
36
|
-
instance_eval(&block) if block_given?
|
37
|
-
self
|
38
|
-
end
|
39
|
-
|
40
|
-
# @api private
|
41
|
-
def visit(node, opts = {})
|
42
|
-
meth, rest = node
|
43
|
-
public_send(:"visit_#{meth}", rest, opts)
|
44
|
-
end
|
45
|
-
|
46
|
-
# @api private
|
47
|
-
def visit_set(node, opts = {})
|
48
|
-
target = (key = opts[:key]) ? self.class.new : self
|
49
|
-
|
50
|
-
node.map { |child| target.visit(child, opts) }
|
51
|
-
|
52
|
-
return unless key
|
53
|
-
|
54
|
-
target_info = opts[:member] ? target.to_h : target.to_h
|
55
|
-
type = keys[key][:array] ? 'array' : 'hash'
|
56
|
-
|
57
|
-
keys.update(key => { **keys[key], type: type, **target_info })
|
58
|
-
end
|
59
|
-
|
60
|
-
# @api private
|
61
|
-
def visit_and(node, opts = {})
|
62
|
-
left, right = node
|
63
|
-
|
64
|
-
visit(left, opts)
|
65
|
-
visit(right, opts)
|
66
|
-
end
|
67
|
-
|
68
|
-
def visit_not(_node, opts = {})
|
69
|
-
keys[opts[:key]][@config.nullable_type] = true
|
70
|
-
end
|
71
|
-
|
72
|
-
# @api private
|
73
|
-
def visit_implication(node, opts = {})
|
74
|
-
node.each do |el|
|
75
|
-
opts = opts.merge(required: false)
|
76
|
-
visit(el, opts)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
# @api private
|
81
|
-
def visit_each(node, opts = {})
|
82
|
-
visit(node, opts.merge(member: true))
|
83
|
-
end
|
84
|
-
|
85
|
-
# @api private
|
86
|
-
def visit_key(node, opts = {})
|
87
|
-
name, rest = node
|
88
|
-
opts = opts.merge(key: name)
|
89
|
-
opts = opts.merge(required: true)
|
90
|
-
visit(rest, opts)
|
91
|
-
end
|
92
|
-
|
93
|
-
# @api private
|
94
|
-
def visit_predicate(node, opts = {})
|
95
|
-
name, rest = node
|
96
|
-
|
97
|
-
key = opts[:key]
|
98
|
-
|
99
|
-
if name.equal?(:key?)
|
100
|
-
keys[rest[0][1]] = { required: opts.fetch(:required, true) }
|
101
|
-
elsif name.equal?(:array?)
|
102
|
-
keys[key][:array] = true
|
103
|
-
elsif name.equal?(:included_in?)
|
104
|
-
enums = rest[0][1]
|
105
|
-
enums += [nil] if opts.fetch(@config.nullable_type, false)
|
106
|
-
keys[key][:enum] = enums
|
107
|
-
elsif PREDICATE_TO_TYPE[name]
|
108
|
-
keys[key][:type] = PREDICATE_TO_TYPE[name]
|
109
|
-
else
|
110
|
-
description = predicate_description(name.to_s, rest[0][1].to_s)
|
111
|
-
if keys[key][:description].to_s.empty?
|
112
|
-
keys[key][:description] = description unless description.to_s.empty?
|
113
|
-
else
|
114
|
-
keys[key][:description] += ", #{description}" unless description.to_s.empty?
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
def predicate_description(name, value)
|
120
|
-
::I18n.t("contract.descriptions.#{name}", value: value, default: '')
|
121
|
-
end
|
122
|
-
|
123
|
-
def to_swagger
|
124
|
-
DocumentationGenerator.new(@config).generate_documentation(keys)
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
@@ -1,144 +0,0 @@
|
|
1
|
-
module Dry
|
2
|
-
module Swagger
|
3
|
-
class StructParser
|
4
|
-
PREDICATE_TYPES = {
|
5
|
-
String: 'string',
|
6
|
-
Integer: 'integer',
|
7
|
-
Bool: 'boolean',
|
8
|
-
Float: 'float',
|
9
|
-
Date: 'date',
|
10
|
-
DateTime: 'datetime',
|
11
|
-
Time: 'time'
|
12
|
-
}.freeze
|
13
|
-
|
14
|
-
attr_reader :keys
|
15
|
-
|
16
|
-
def initialize
|
17
|
-
@keys = {}
|
18
|
-
@config = Dry::Swagger::Config::StructConfiguration
|
19
|
-
end
|
20
|
-
|
21
|
-
def to_h
|
22
|
-
{ keys: keys }
|
23
|
-
end
|
24
|
-
|
25
|
-
def call(dto, &block)
|
26
|
-
@keys = {}
|
27
|
-
visit(dto.schema.to_ast)
|
28
|
-
instance_eval(&block) if block_given?
|
29
|
-
self
|
30
|
-
end
|
31
|
-
|
32
|
-
def visit(node, opts = {})
|
33
|
-
meth, rest = node
|
34
|
-
public_send(:"visit_#{meth}", rest, opts)
|
35
|
-
end
|
36
|
-
|
37
|
-
def visit_constructor(node, opts = {})
|
38
|
-
visit(node[0], opts)
|
39
|
-
end
|
40
|
-
|
41
|
-
def visit_schema(node, opts = {})
|
42
|
-
target = (key = opts[:key]) ? self.class.new : self
|
43
|
-
|
44
|
-
required = opts.fetch(:required, true)
|
45
|
-
nullable = opts.fetch(:nullable, false)
|
46
|
-
|
47
|
-
node[0].each do |child|
|
48
|
-
target.visit(child)
|
49
|
-
end
|
50
|
-
|
51
|
-
return unless key
|
52
|
-
|
53
|
-
target_info = target.to_h if opts[:member]
|
54
|
-
|
55
|
-
type = opts[:array]? 'array' : 'hash'
|
56
|
-
|
57
|
-
definition = {
|
58
|
-
type: type,
|
59
|
-
required: required,
|
60
|
-
@config.nullable_type => nullable,
|
61
|
-
**target_info
|
62
|
-
}
|
63
|
-
|
64
|
-
if opts[:oneOf]
|
65
|
-
keys[key] = keys[key] ? keys[key] << definition : [definition]
|
66
|
-
else
|
67
|
-
keys[key] = definition
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def visit_key(node, opts = {})
|
72
|
-
name, required, rest = node
|
73
|
-
opts[:key] = name
|
74
|
-
opts[:required] = required
|
75
|
-
visit(rest, opts)
|
76
|
-
end
|
77
|
-
|
78
|
-
def visit_constrained(node, opts = {})
|
79
|
-
node.each {|it| visit(it, opts) }
|
80
|
-
end
|
81
|
-
|
82
|
-
def visit_nominal(_node, _opts); end
|
83
|
-
|
84
|
-
def visit_predicate(node, opts = {})
|
85
|
-
name, rest = node
|
86
|
-
type = rest[0][1]
|
87
|
-
|
88
|
-
if name.equal?(:type?)
|
89
|
-
type = type.to_s.to_sym
|
90
|
-
return unless PREDICATE_TYPES[type]
|
91
|
-
|
92
|
-
type_definition = {
|
93
|
-
type: PREDICATE_TYPES[type],
|
94
|
-
required: opts.fetch(:required),
|
95
|
-
@config.nullable_type => opts.fetch(:nullable, false)
|
96
|
-
}
|
97
|
-
|
98
|
-
type_definition[:array] = opts[:array] if opts[:array]
|
99
|
-
|
100
|
-
keys[opts[:key]] = type_definition
|
101
|
-
elsif name.equal?(:included_in?)
|
102
|
-
type += [nil] if opts.fetch(:nullable, false)
|
103
|
-
keys[opts[:key]][:enum] = type
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
def visit_and(node, opts = {})
|
108
|
-
left, right = node
|
109
|
-
|
110
|
-
visit(left, opts)
|
111
|
-
visit(right, opts)
|
112
|
-
end
|
113
|
-
|
114
|
-
def visit_enum(node, opts = {})
|
115
|
-
visit(node[0], opts)
|
116
|
-
end
|
117
|
-
|
118
|
-
def visit_sum(node, opts = {})
|
119
|
-
if node[0][0].equal?(:constrained)
|
120
|
-
opts[:nullable] = true
|
121
|
-
visit(node[1], opts) # ignore NilClass constrained
|
122
|
-
elsif node[0][0].equal?(:struct) || node[0][0].equal?(:sum)
|
123
|
-
opts[:oneOf] = true
|
124
|
-
node.each { |child| visit(child, opts) unless child.is_a?(Hash) }
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
def visit_struct(node, opts = {})
|
129
|
-
opts[:member] = true
|
130
|
-
|
131
|
-
visit(node[1], opts)
|
132
|
-
end
|
133
|
-
|
134
|
-
def visit_array(node, opts = {})
|
135
|
-
opts[:array] = true
|
136
|
-
visit(node[0], opts)
|
137
|
-
end
|
138
|
-
|
139
|
-
def to_swagger
|
140
|
-
DocumentationGenerator.new(@config).generate_documentation(keys)
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|