jsonapi-swagger 0.5.0 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +35 -3
- data/lib/generators/jsonapi/swagger/swagger_generator.rb +83 -13
- data/lib/generators/jsonapi/swagger/templates/swagger.json.erb +319 -0
- data/lib/generators/jsonapi/swagger/templates/swagger.rb.erb +8 -4
- data/lib/i18n/en.yml +1 -0
- data/lib/i18n/zh-CN.yml +1 -0
- data/lib/jsonapi/swagger.rb +34 -0
- data/lib/jsonapi/swagger/json.rb +31 -0
- data/lib/jsonapi/swagger/resource.rb +33 -0
- data/lib/jsonapi/swagger/resources/fast_jsonapi_resource.rb +39 -0
- data/lib/jsonapi/swagger/resources/jsonapi_resource.rb +18 -0
- data/lib/jsonapi/swagger/resources/serializable_resource.rb +45 -0
- data/lib/jsonapi/swagger/version.rb +1 -1
- metadata +15 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dab83649ba5e56cfa51c621a9fb47add67a4a2ae889d44b6ba4b3bc1e712fea8
|
4
|
+
data.tar.gz: 94a539114d9f3ae6b0da32f79562e319e75219b354e90266986168507d141fa7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e7625c8893c464aecde1b5987776a8be6a9f4599ef6e2870f27c18d3fe3e82c25dd3eabe523953f5caa43542bcf8897afaf2df4703edf137a2b8d3f37cb26212
|
7
|
+
data.tar.gz: 48ad3673d7335ed35b9fbe132aa2511570760fa22dc817c97b54a75affcccf744606665695b5b28e3de594952cd445d5798913a555bc956dfd9ba487dd1ee39c
|
data/README.md
CHANGED
@@ -2,7 +2,8 @@
|
|
2
2
|
|
3
3
|
Generate JSONAPI Swagger Doc.
|
4
4
|
|
5
|
-
[](https://rubygems.org/gems/jsonapi-swagger)
|
5
|
+
[](https://rubygems.org/gems/jsonapi-swagger)
|
6
|
+
[](https://github.com/superiorlu/jsonapi-swagger/blob/master/LICENSE)
|
6
7
|
|
7
8
|
[](https://i.loli.net/2019/05/05/5ccebf5e782b7.gif)
|
8
9
|
|
@@ -24,10 +25,40 @@ Or install it yourself as:
|
|
24
25
|
|
25
26
|
## Usage
|
26
27
|
|
28
|
+
1. config jsonapi swagger
|
29
|
+
```rb
|
30
|
+
# config/initializers/swagger.rb
|
31
|
+
Jsonapi::Swagger.config do |config|
|
32
|
+
config.use_rswag = false
|
33
|
+
config.version = '2.0'
|
34
|
+
config.info = { title: 'API V1', version: 'V1'}
|
35
|
+
config.file_path = 'v1/swagger.json'
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
39
|
+
2. generate swagger.json
|
40
|
+
|
41
|
+
```sh
|
42
|
+
# gen swagger/v1/swagger.json
|
43
|
+
bundle exec rails generate jsonapi:swagger User # UserResource < JSONAPI::Resource
|
44
|
+
```
|
45
|
+
|
46
|
+
3. additional
|
47
|
+
|
48
|
+
use `rswag`, have to run
|
49
|
+
|
27
50
|
```sh
|
28
|
-
|
51
|
+
# gen swagger/v1/swagger.json
|
52
|
+
bundle exec rails rswag:specs:swaggerize
|
29
53
|
```
|
30
54
|
|
55
|
+
## RoadMap
|
56
|
+
|
57
|
+
- [x] immutable resources
|
58
|
+
- [x] filter/sort resources
|
59
|
+
- [x] mutable resources
|
60
|
+
- [x] generate swagger.json without rswag
|
61
|
+
|
31
62
|
## Resource
|
32
63
|
|
33
64
|
- [JSONAPI](https://jsonapi.org/)
|
@@ -36,4 +67,5 @@ rails generate jsonapi:swagger User # UserResponse < JSONAPI::Resource
|
|
36
67
|
|
37
68
|
## Contributing
|
38
69
|
|
39
|
-
Bug reports and pull requests are welcome on GitHub at
|
70
|
+
Bug reports and pull requests are welcome on GitHub at
|
71
|
+
https://github.com/superiorlu/jsonapi-swagger.
|
@@ -4,15 +4,54 @@ module Jsonapi
|
|
4
4
|
source_root File.expand_path('templates', __dir__)
|
5
5
|
|
6
6
|
def create_swagger_file
|
7
|
-
|
7
|
+
if Jsonapi::Swagger.use_rswag
|
8
|
+
template 'swagger.rb.erb', spec_file
|
9
|
+
else
|
10
|
+
template 'swagger.json.erb', json_file
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def doc
|
17
|
+
@doc ||= swagger_json.parse_doc
|
18
|
+
end
|
19
|
+
|
20
|
+
def spec_file
|
21
|
+
@spec_file ||= File.join(
|
8
22
|
'spec/requests',
|
9
23
|
class_path,
|
10
24
|
spec_file_name
|
11
25
|
)
|
12
|
-
template 'swagger.rb.erb', swagger_file
|
13
26
|
end
|
14
27
|
|
15
|
-
|
28
|
+
def json_file
|
29
|
+
@json_file ||= File.join(
|
30
|
+
'swagger',
|
31
|
+
class_path,
|
32
|
+
swagger_file_path
|
33
|
+
)
|
34
|
+
end
|
35
|
+
|
36
|
+
def swagger_version
|
37
|
+
Jsonapi::Swagger.version
|
38
|
+
end
|
39
|
+
|
40
|
+
def swagger_info
|
41
|
+
JSON.pretty_generate(Jsonapi::Swagger.info)
|
42
|
+
end
|
43
|
+
|
44
|
+
def swagger_base_path
|
45
|
+
Jsonapi::Swagger.base_path
|
46
|
+
end
|
47
|
+
|
48
|
+
def swagger_file_path
|
49
|
+
Jsonapi::Swagger.file_path
|
50
|
+
end
|
51
|
+
|
52
|
+
def swagger_json
|
53
|
+
@swagger_json ||= Jsonapi::Swagger::Json.new(json_file)
|
54
|
+
end
|
16
55
|
|
17
56
|
def spec_file_name
|
18
57
|
"#{file_name.downcase.pluralize}_spec.rb"
|
@@ -38,20 +77,24 @@ module Jsonapi
|
|
38
77
|
t(:sortable_fields) + ': (-)' + sortable_fields.join(',')
|
39
78
|
end
|
40
79
|
|
80
|
+
def ori_sortable_fields_desc
|
81
|
+
tt(:sortable_fields) + ': (-)' + sortable_fields.join(',')
|
82
|
+
end
|
83
|
+
|
41
84
|
def model_klass
|
42
|
-
|
85
|
+
file_name.camelize.safe_constantize
|
43
86
|
end
|
44
87
|
|
45
88
|
def resource_klass
|
46
|
-
|
89
|
+
@resource_klass ||= Jsonapi::Swagger::Resource.with(model_class_name)
|
47
90
|
end
|
48
91
|
|
49
92
|
def attributes
|
50
|
-
resource_klass.
|
93
|
+
resource_klass.attributes.except(:id)
|
51
94
|
end
|
52
95
|
|
53
96
|
def relationships
|
54
|
-
resource_klass.
|
97
|
+
resource_klass.relationships
|
55
98
|
end
|
56
99
|
|
57
100
|
def sortable_fields
|
@@ -70,16 +113,34 @@ module Jsonapi
|
|
70
113
|
resource_klass.filters
|
71
114
|
end
|
72
115
|
|
73
|
-
def
|
116
|
+
def mutable?
|
117
|
+
resource_klass.mutable?
|
118
|
+
end
|
119
|
+
|
120
|
+
def attribute_default
|
121
|
+
Jsonapi::Swagger.attribute_default
|
122
|
+
end
|
123
|
+
|
124
|
+
def transform_method
|
125
|
+
@transform_method ||= resource_klass.transform_method if resource_klass.respond_to?(:transform_method)
|
126
|
+
end
|
127
|
+
|
128
|
+
def columns_with_comment(need_encoding: true)
|
74
129
|
@columns_with_comment ||= {}.tap do |clos|
|
130
|
+
clos.default_proc = proc do |h, k|
|
131
|
+
h[k] = attribute_default
|
132
|
+
end
|
75
133
|
model_klass.columns.each do |col|
|
76
|
-
|
134
|
+
col_name = transform_method ? col.name.send(transform_method) : col.name
|
135
|
+
is_array = col.respond_to?(:array) ? col.array : false
|
136
|
+
clos[col_name.to_sym] = { type: swagger_type(col), items_type: col.type, is_array: is_array, nullable: col.null, comment: col.comment }
|
137
|
+
clos[col_name.to_sym][:comment] = safe_encode(col.comment) if need_encoding
|
77
138
|
end
|
78
139
|
end
|
79
140
|
end
|
80
141
|
|
81
142
|
def swagger_type(column)
|
82
|
-
return 'array' if column.array
|
143
|
+
return 'array' if column.respond_to?(:array) && column.array
|
83
144
|
|
84
145
|
case column.type
|
85
146
|
when :bigint, :integer then 'integer'
|
@@ -88,15 +149,24 @@ module Jsonapi
|
|
88
149
|
end
|
89
150
|
end
|
90
151
|
|
152
|
+
def relation_table_name(relation)
|
153
|
+
return relation.class_name.tableize if relation.respond_to?(:class_name)
|
154
|
+
return relation.name if relation.respond_to?(:name)
|
155
|
+
end
|
156
|
+
|
91
157
|
def t(key, options={})
|
158
|
+
content = tt(key, options)
|
159
|
+
safe_encode(content)
|
160
|
+
end
|
161
|
+
|
162
|
+
def tt(key, options={})
|
92
163
|
options[:scope] = :jsonapi_swagger
|
93
164
|
options[:default] = key.to_s.humanize
|
94
|
-
|
95
|
-
safe_encode(content)
|
165
|
+
I18n.t(key, options)
|
96
166
|
end
|
97
167
|
|
98
168
|
def safe_encode(content)
|
99
169
|
content&.force_encoding('ASCII-8BIT')
|
100
170
|
end
|
101
171
|
end
|
102
|
-
end
|
172
|
+
end
|
@@ -0,0 +1,319 @@
|
|
1
|
+
{
|
2
|
+
"swagger": "<%= swagger_version %>",
|
3
|
+
"info": <%= swagger_info %>,
|
4
|
+
"basePath" : "<%= swagger_base_path %>",
|
5
|
+
<%-
|
6
|
+
def list_resource_parameters
|
7
|
+
[].tap do |parameters|
|
8
|
+
parameters << { name: 'page[number]', in: :query, type: :string, description: tt(:page_num), required: false }
|
9
|
+
parameters << { name: 'page[size]', in: :query, type: :string, description: tt(:page_size), required: false }
|
10
|
+
if sortable_fields.present?
|
11
|
+
parameters << { name: 'sort', in: :query, type: :string, description: ori_sortable_fields_desc, required: false }
|
12
|
+
end
|
13
|
+
if relationships.present?
|
14
|
+
parameters << { name: :include, in: :query, type: :string, description: tt(:include_related_data), required: false }
|
15
|
+
end
|
16
|
+
filters.each do |filter_attr, filter_config|
|
17
|
+
parameters << { name: :"filter[#{filter_attr}]", in: :query, type: :string, description: tt(:filter_field), required: false}
|
18
|
+
end
|
19
|
+
parameters << { name: :"fields[#{route_resouces}]", in: :query, type: :string, description: tt(:display_field), required: false }
|
20
|
+
relationships.each_value do |relation|
|
21
|
+
parameters << { name: :"fields[#{relation_table_name(relation)}]", in: :query, type: :string, description: tt(:display_field), required: false }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def show_resource_parameters
|
27
|
+
[].tap do |parameters|
|
28
|
+
parameters << { name: :id, in: :path, type: :integer, description: 'ID', required: true }
|
29
|
+
if relationships.present?
|
30
|
+
parameters << { name: :include, in: :query, type: :string, description: tt(:include_related_data), required: false }
|
31
|
+
end
|
32
|
+
parameters << { name: :"fields[#{route_resouces}]", in: :query, type: :string, description: tt(:display_field), required: false }
|
33
|
+
relationships.each_value do |relation|
|
34
|
+
parameters << { name: :"fields[#{relation_table_name(relation)}]", in: :query, type: :string, description: tt(:display_field), required: false }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def create_resource_parameters
|
40
|
+
parameters = {
|
41
|
+
name: :data,
|
42
|
+
in: :body,
|
43
|
+
type: :object,
|
44
|
+
properties: {
|
45
|
+
data: {
|
46
|
+
type: :object,
|
47
|
+
properties: {
|
48
|
+
type: { type: :string, default: route_resouces },
|
49
|
+
attributes: {
|
50
|
+
type: :object,
|
51
|
+
properties: properties(attrs: creatable_fields)
|
52
|
+
}
|
53
|
+
}
|
54
|
+
},
|
55
|
+
},
|
56
|
+
description: tt(:request_body)
|
57
|
+
}
|
58
|
+
parameters[:properties][:data][:properties][:relationships] ||= {}
|
59
|
+
parameters[:properties][:data][:properties][:relationships] = { type: :object, properties: create_relationships_properties }
|
60
|
+
parameters
|
61
|
+
end
|
62
|
+
|
63
|
+
def patch_resource_parameters
|
64
|
+
patch_parameters = create_resource_parameters.dup
|
65
|
+
patch_parameters[:properties][:data][:properties][:id] ||= {}
|
66
|
+
patch_parameters[:properties][:data][:properties][:id].merge!({ type: :integer, description: 'ID' })
|
67
|
+
parameters = [{ name: :id, in: :path, type: :integer, description: 'ID', required: true }]
|
68
|
+
parameters << patch_parameters
|
69
|
+
parameters
|
70
|
+
end
|
71
|
+
|
72
|
+
def delete_resource_parameters
|
73
|
+
[{ name: :id, in: :path, type: :integer, description: 'ID', required: true }]
|
74
|
+
end
|
75
|
+
|
76
|
+
def properties(attrs: [])
|
77
|
+
Hash.new{|h, k| h[k] = {}} .tap do |props|
|
78
|
+
attrs.each do |attr|
|
79
|
+
columns = columns_with_comment(need_encoding: false)
|
80
|
+
props[attr][:type] = columns[attr][:type]
|
81
|
+
props[attr][:items] = { type: columns[attr][:items_type] } if columns[attr][:is_array]
|
82
|
+
props[attr][:'x-nullable'] = columns[attr][:nullable]
|
83
|
+
props[attr][:description] = columns[attr][:comment]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def relationships_properties
|
89
|
+
{}.tap do |relat_props|
|
90
|
+
relationships.each do |relation_name, relation|
|
91
|
+
relation_name_camelize = relation_name.to_s.camelize
|
92
|
+
relat_props[relation_name] = {
|
93
|
+
type: :object,
|
94
|
+
properties: {
|
95
|
+
links: {
|
96
|
+
type: :object,
|
97
|
+
properties: {
|
98
|
+
self: { type: :string, description: tt(:associate_list_link, model: relation_name_camelize) },
|
99
|
+
related: { type: :string, description: tt(:related_link, model: relation_name_camelize) },
|
100
|
+
},
|
101
|
+
description: tt(:related_link, model: relation_name_camelize)
|
102
|
+
},
|
103
|
+
},
|
104
|
+
description: tt(:related_model, model: relation_name_camelize)
|
105
|
+
}
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def create_relationships_properties
|
111
|
+
{}.tap do |relat_props|
|
112
|
+
relationships.each do |relation_name, relation|
|
113
|
+
relation_name_camelize = relation_name.to_s.camelize
|
114
|
+
relat_props[relation_name] = {
|
115
|
+
type: :object,
|
116
|
+
properties: {
|
117
|
+
data: {
|
118
|
+
type: :array,
|
119
|
+
items: {
|
120
|
+
type: :object,
|
121
|
+
properties: {
|
122
|
+
type: { type: :string, default: relation.table_name },
|
123
|
+
id: { type: :string, description: "#{relation_name_camelize} ID" },
|
124
|
+
},
|
125
|
+
},
|
126
|
+
description: tt(:related_ids, model: relation_name_camelize)
|
127
|
+
}
|
128
|
+
},
|
129
|
+
description: tt(:related_ids, model: relation_name_camelize)
|
130
|
+
}
|
131
|
+
if relation.try(:belongs_to?)
|
132
|
+
relat_props[relation_name][:properties][:data] = {
|
133
|
+
type: :object,
|
134
|
+
properties: {
|
135
|
+
type: { type: :string, default: relation.table_name },
|
136
|
+
id: { type: :string, description: "#{relation_name_camelize} ID" },
|
137
|
+
},
|
138
|
+
description: tt(:related_id, model: relation_name_camelize)
|
139
|
+
}
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def list_resource_responses
|
146
|
+
{
|
147
|
+
'200' => {
|
148
|
+
description: tt(:get_list),
|
149
|
+
schema: {
|
150
|
+
type: :object,
|
151
|
+
properties: {
|
152
|
+
data: {
|
153
|
+
type: :array,
|
154
|
+
items: {
|
155
|
+
type: :object,
|
156
|
+
properties: {
|
157
|
+
id: { type: :string, description: 'ID'},
|
158
|
+
links: {
|
159
|
+
type: :object,
|
160
|
+
properties: {
|
161
|
+
self: { type: :string, description: tt(:detail_link) },
|
162
|
+
},
|
163
|
+
description: tt(:detail_link)
|
164
|
+
},
|
165
|
+
attributes: {
|
166
|
+
type: :object,
|
167
|
+
properties: properties(attrs: attributes.each_key),
|
168
|
+
description: tt(:attributes)
|
169
|
+
},
|
170
|
+
relationships: {
|
171
|
+
type: :object,
|
172
|
+
properties: relationships_properties,
|
173
|
+
description: tt(:associate_data)
|
174
|
+
}
|
175
|
+
},
|
176
|
+
},
|
177
|
+
description: tt(:data)
|
178
|
+
},
|
179
|
+
meta: {
|
180
|
+
type: :object,
|
181
|
+
properties: {
|
182
|
+
record_count: { type: :integer, description: tt(:record_count)},
|
183
|
+
page_count: { type: :integer, description: tt(:page_count)},
|
184
|
+
},
|
185
|
+
description: tt(:meta)
|
186
|
+
},
|
187
|
+
links: {
|
188
|
+
type: :object,
|
189
|
+
properties: {
|
190
|
+
first: { type: :string, description: tt(:first_page_link) },
|
191
|
+
next: { type: :string, description: tt(:next_page_link) },
|
192
|
+
last: { type: :string, description: tt(:last_page_link) },
|
193
|
+
},
|
194
|
+
description: tt(:page_links) },
|
195
|
+
},
|
196
|
+
required: [:data]
|
197
|
+
}
|
198
|
+
}
|
199
|
+
}
|
200
|
+
end
|
201
|
+
|
202
|
+
def show_resource_responses
|
203
|
+
{
|
204
|
+
'200' => {
|
205
|
+
description: tt(:get_detail),
|
206
|
+
schema: show_resource_schema
|
207
|
+
}
|
208
|
+
}
|
209
|
+
end
|
210
|
+
|
211
|
+
def create_resource_responses
|
212
|
+
{
|
213
|
+
'201' => {
|
214
|
+
description: tt(:create),
|
215
|
+
schema: show_resource_schema
|
216
|
+
}
|
217
|
+
}
|
218
|
+
end
|
219
|
+
|
220
|
+
def delete_resource_responses
|
221
|
+
{
|
222
|
+
'204' => { description: tt(:delete) }
|
223
|
+
}
|
224
|
+
end
|
225
|
+
|
226
|
+
def show_resource_schema
|
227
|
+
{
|
228
|
+
type: :object,
|
229
|
+
properties: {
|
230
|
+
data: {
|
231
|
+
type: :object,
|
232
|
+
properties: {
|
233
|
+
id: { type: :string, description: 'ID'},
|
234
|
+
type: { type: :string, description: 'Type'},
|
235
|
+
links: {
|
236
|
+
type: :object,
|
237
|
+
properties: {
|
238
|
+
self: { type: :string, description: tt(:detail_link) },
|
239
|
+
},
|
240
|
+
description: tt(:detail_link)
|
241
|
+
},
|
242
|
+
attributes: {
|
243
|
+
type: :object,
|
244
|
+
properties: properties(attrs: attributes.each_key),
|
245
|
+
description: tt(:attributes)
|
246
|
+
},
|
247
|
+
relationships: {
|
248
|
+
type: :object,
|
249
|
+
properties: relationships_properties,
|
250
|
+
description: tt(:associate_data)
|
251
|
+
}
|
252
|
+
},
|
253
|
+
description: tt(:data)
|
254
|
+
}
|
255
|
+
},
|
256
|
+
required: [:data]
|
257
|
+
}
|
258
|
+
end
|
259
|
+
|
260
|
+
doc['paths']["/#{route_resouces}"] = {
|
261
|
+
get: {
|
262
|
+
summary: "#{route_resouces} #{tt(:list)}",
|
263
|
+
tags: [route_resouces],
|
264
|
+
produces: ['application/vnd.api+json'],
|
265
|
+
parameters: list_resource_parameters,
|
266
|
+
responses: list_resource_responses
|
267
|
+
}
|
268
|
+
}
|
269
|
+
|
270
|
+
doc['paths']["/#{route_resouces}/{id}"] = {
|
271
|
+
get: {
|
272
|
+
summary: "#{route_resouces} #{tt(:detail)}",
|
273
|
+
tags: [route_resouces],
|
274
|
+
produces: ['application/vnd.api+json'],
|
275
|
+
parameters: show_resource_parameters,
|
276
|
+
responses: show_resource_responses
|
277
|
+
}
|
278
|
+
}
|
279
|
+
|
280
|
+
if mutable?
|
281
|
+
doc['paths']["/#{route_resouces}"].merge!({
|
282
|
+
post: {
|
283
|
+
summary: "#{route_resouces} #{tt(:create)}",
|
284
|
+
tags: [route_resouces],
|
285
|
+
consumes: ['application/vnd.api+json'],
|
286
|
+
produces: ['application/vnd.api+json'],
|
287
|
+
parameters: [create_resource_parameters],
|
288
|
+
responses: create_resource_responses
|
289
|
+
}
|
290
|
+
})
|
291
|
+
|
292
|
+
doc['paths']["/#{route_resouces}/{id}"].merge!({
|
293
|
+
patch: {
|
294
|
+
summary: "#{route_resouces} #{tt(:patch)}",
|
295
|
+
tags: [route_resouces],
|
296
|
+
consumes: ['application/vnd.api+json'],
|
297
|
+
produces: ['application/vnd.api+json'],
|
298
|
+
parameters: patch_resource_parameters,
|
299
|
+
responses: show_resource_responses
|
300
|
+
}
|
301
|
+
})
|
302
|
+
|
303
|
+
doc['paths']["/#{route_resouces}/{id}"].merge!({
|
304
|
+
delete: {
|
305
|
+
summary: "#{route_resouces} #{tt(:delete)}",
|
306
|
+
tags: [route_resouces],
|
307
|
+
produces: ['application/vnd.api+json'],
|
308
|
+
parameters: delete_resource_parameters,
|
309
|
+
responses: delete_resource_responses
|
310
|
+
}
|
311
|
+
})
|
312
|
+
else
|
313
|
+
doc['paths']["/#{route_resouces}"].delete(:post)
|
314
|
+
doc['paths']["/#{route_resouces}/{id}"].delete(:patch)
|
315
|
+
doc['paths']["/#{route_resouces}/{id}"].delete(:delete)
|
316
|
+
end
|
317
|
+
-%>
|
318
|
+
"paths": <%= JSON.pretty_generate(doc['paths'] ) %>
|
319
|
+
}
|
@@ -3,7 +3,11 @@ RSpec.describe '<%= resouces_name %>', type: :request do
|
|
3
3
|
let(:include) {''} #see https://github.com/domaindrivendev/rswag/issues/188
|
4
4
|
|
5
5
|
before(:each) do
|
6
|
+
<% if defined?(FactoryBot) -%>
|
6
7
|
@<%= model_name %> = create :<%= model_name %>
|
8
|
+
<% else -%>
|
9
|
+
@<%= model_name %> = <%= model_class_name %>.create
|
10
|
+
<% end -%>
|
7
11
|
end
|
8
12
|
|
9
13
|
path '/<%= route_resouces %>' do
|
@@ -22,7 +26,7 @@ RSpec.describe '<%= resouces_name %>', type: :request do
|
|
22
26
|
<% end -%>
|
23
27
|
parameter name: :'fields[<%= route_resouces %>]', in: :query, type: :string, description: '<%= t(:display_field) %>', required: false
|
24
28
|
<% relationships.each_value do |relation| -%>
|
25
|
-
parameter name: :'fields[<%= relation
|
29
|
+
parameter name: :'fields[<%= relation_table_name(relation) %>]', in: :query, type: :string, description: '<%= t(:display_field) %>', required: false
|
26
30
|
<% end -%>
|
27
31
|
response '200', '<%= t(:get_list) %>' do
|
28
32
|
schema type: :object,
|
@@ -109,7 +113,7 @@ RSpec.describe '<%= resouces_name %>', type: :request do
|
|
109
113
|
<% end -%>
|
110
114
|
parameter name: :'fields[<%= route_resouces %>]', in: :query, type: :string, description: '<%= t(:display_field) %>', required: false
|
111
115
|
<% relationships.each_value do |relation| -%>
|
112
|
-
parameter name: :'fields[<%= relation
|
116
|
+
parameter name: :'fields[<%= relation_table_name(relation) %>]', in: :query, type: :string, description: '<%= t(:display_field) %>', required: false
|
113
117
|
<% end -%>
|
114
118
|
response '200', '<%= t(:get_detail) %>' do
|
115
119
|
schema type: :object,
|
@@ -169,7 +173,7 @@ RSpec.describe '<%= resouces_name %>', type: :request do
|
|
169
173
|
end
|
170
174
|
end
|
171
175
|
|
172
|
-
<% if
|
176
|
+
<% if mutable? -%>
|
173
177
|
path '/<%= route_resouces %>' do
|
174
178
|
post '<%= route_resouces %> <%= t(:create) %>' do
|
175
179
|
tags '<%= route_resouces %>'
|
@@ -200,7 +204,7 @@ RSpec.describe '<%= resouces_name %>', type: :request do
|
|
200
204
|
<%= relation_name %>: {
|
201
205
|
type: :object,
|
202
206
|
properties: {
|
203
|
-
<% if relation.belongs_to? -%>
|
207
|
+
<% if relation.try(:belongs_to?) -%>
|
204
208
|
data: {
|
205
209
|
type: :object,
|
206
210
|
properties: {
|
data/lib/i18n/en.yml
CHANGED
data/lib/i18n/zh-CN.yml
CHANGED
data/lib/jsonapi/swagger.rb
CHANGED
@@ -2,9 +2,43 @@
|
|
2
2
|
|
3
3
|
require 'jsonapi/swagger/version'
|
4
4
|
require 'jsonapi/swagger/railtie' if defined?(Rails)
|
5
|
+
require 'jsonapi/swagger/json'
|
6
|
+
require 'jsonapi/swagger/resource'
|
5
7
|
|
6
8
|
module Jsonapi
|
7
9
|
module Swagger
|
8
10
|
class Error < StandardError; end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
attr_accessor :version, :info, :file_path, :base_path, :use_rswag
|
14
|
+
|
15
|
+
def config
|
16
|
+
yield self
|
17
|
+
end
|
18
|
+
|
19
|
+
def version
|
20
|
+
@version ||= '2.0'
|
21
|
+
end
|
22
|
+
|
23
|
+
def info
|
24
|
+
@info ||= { title: 'API V1', version: 'V1' }
|
25
|
+
end
|
26
|
+
|
27
|
+
def file_path
|
28
|
+
@file_path ||= 'v1/swagger.json'
|
29
|
+
end
|
30
|
+
|
31
|
+
def base_path
|
32
|
+
@base_path
|
33
|
+
end
|
34
|
+
|
35
|
+
def use_rswag
|
36
|
+
@use_rswag ||= false
|
37
|
+
end
|
38
|
+
|
39
|
+
def attribute_default
|
40
|
+
@attribute_default ||= { type: :string, nullable: true, comment: nil }
|
41
|
+
end
|
42
|
+
end
|
9
43
|
end
|
10
44
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Jsonapi
|
2
|
+
module Swagger
|
3
|
+
class Json
|
4
|
+
|
5
|
+
attr_accessor :path
|
6
|
+
|
7
|
+
def initialize(path = 'swagger/v1/swagger.json')
|
8
|
+
@path = path
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse_doc
|
12
|
+
@doc ||= JSON.parse(load) rescue Hash.new{ |h, k| h[k]= {} }
|
13
|
+
end
|
14
|
+
|
15
|
+
def base_path
|
16
|
+
Jsonapi::Swagger.base_path
|
17
|
+
end
|
18
|
+
|
19
|
+
def load
|
20
|
+
@data ||= if File.exist?(path)
|
21
|
+
IO.read(path)
|
22
|
+
else
|
23
|
+
puts "create swagger.json in #{path}"
|
24
|
+
'{}'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
module Jsonapi
|
3
|
+
module Swagger
|
4
|
+
class Resource
|
5
|
+
def self.with(model_class_name)
|
6
|
+
if Object.const_defined?("#{model_class_name}Resource")
|
7
|
+
@resource_class = "#{model_class_name}Resource".safe_constantize
|
8
|
+
unless @resource_class < JSONAPI::Resource
|
9
|
+
raise Jsonapi::Swagger::Error, "#{@resource_class.class} is not Subclass of JSONAPI::Resource!"
|
10
|
+
end
|
11
|
+
require 'jsonapi/swagger/resources/jsonapi_resource'
|
12
|
+
return Jsonapi::Swagger::JsonapiResource.new(@resource_class)
|
13
|
+
elsif Object.const_defined?("Serializable#{model_class_name}")
|
14
|
+
@resource_class = "Serializable#{model_class_name}".safe_constantize
|
15
|
+
unless @resource_class < JSONAPI::Serializable::Resource
|
16
|
+
raise Jsonapi::Swagger::Error, "#{@resource_class.class} is not Subclass of JSONAPI::Serializable::Resource!"
|
17
|
+
end
|
18
|
+
require 'jsonapi/swagger/resources/serializable_resource'
|
19
|
+
return Jsonapi::Swagger::SerializableResource.new(@resource_class)
|
20
|
+
elsif Object.const_defined?("#{model_class_name}Serializer")
|
21
|
+
@resource_class = "#{model_class_name}Serializer".safe_constantize
|
22
|
+
unless @resource_class < FastJsonapi::ObjectSerializer
|
23
|
+
raise Jsonapi::Swagger::Error, "#{@resource_class.class} is not Subclass of FastJsonapi::ObjectSerializer!"
|
24
|
+
end
|
25
|
+
require 'jsonapi/swagger/resources/fast_jsonapi_resource'
|
26
|
+
return Jsonapi::Swagger::FastJsonapiResource.new(@resource_class)
|
27
|
+
else
|
28
|
+
raise Jsonapi::Swagger::Error, "#{model_class_name} not support!"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
module Jsonapi
|
3
|
+
module Swagger
|
4
|
+
class FastJsonapiResource
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
def_delegators :@fr, :attributes_to_serialize, :relationships_to_serialize, :sortable_fields,
|
8
|
+
:creatable_fields, :updatable_fields, :filters, :mutable?, :transform_method
|
9
|
+
|
10
|
+
def initialize(fr)
|
11
|
+
@fr = fr
|
12
|
+
end
|
13
|
+
|
14
|
+
alias attributes attributes_to_serialize
|
15
|
+
alias relationships relationships_to_serialize
|
16
|
+
|
17
|
+
# TODO: fast_jsonapi resource
|
18
|
+
def sortable_fields
|
19
|
+
[]
|
20
|
+
end
|
21
|
+
|
22
|
+
def creatable_fields
|
23
|
+
[]
|
24
|
+
end
|
25
|
+
|
26
|
+
def updatable_fields
|
27
|
+
[]
|
28
|
+
end
|
29
|
+
|
30
|
+
def filters
|
31
|
+
[]
|
32
|
+
end
|
33
|
+
|
34
|
+
def mutable?
|
35
|
+
false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
module Jsonapi
|
3
|
+
module Swagger
|
4
|
+
class JsonapiResource
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
def_delegators :@jr, :_attributes, :_relationships, :sortable_fields,
|
8
|
+
:creatable_fields, :updatable_fields, :filters, :mutable?
|
9
|
+
|
10
|
+
def initialize(jr)
|
11
|
+
@jr = jr
|
12
|
+
end
|
13
|
+
|
14
|
+
alias attributes _attributes
|
15
|
+
alias relationships _relationships
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
module Jsonapi
|
3
|
+
module Swagger
|
4
|
+
class SerializableResource
|
5
|
+
extend Forwardable
|
6
|
+
|
7
|
+
def_delegators :@sr, :type_val, :attribute_blocks, :relationship_blocks, :link_blocks
|
8
|
+
|
9
|
+
def initialize(sr)
|
10
|
+
@sr = sr
|
11
|
+
end
|
12
|
+
|
13
|
+
alias attributes attribute_blocks
|
14
|
+
|
15
|
+
def relationships
|
16
|
+
{}.tap do |relations|
|
17
|
+
relationship_blocks.each do |rel, block|
|
18
|
+
relations[rel] = OpenStruct.new(class_name: rel.to_s)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# TODO: from jsonapi serializable resource
|
24
|
+
def sortable_fields
|
25
|
+
[]
|
26
|
+
end
|
27
|
+
|
28
|
+
def creatable_fields
|
29
|
+
[]
|
30
|
+
end
|
31
|
+
|
32
|
+
def updatable_fields
|
33
|
+
[]
|
34
|
+
end
|
35
|
+
|
36
|
+
def filters
|
37
|
+
[]
|
38
|
+
end
|
39
|
+
|
40
|
+
def mutable?
|
41
|
+
false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsonapi-swagger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- YingRui Lu
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-11-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -28,16 +28,16 @@ dependencies:
|
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 12.3.3
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 12.3.3
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rubocop
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -59,7 +59,7 @@ dependencies:
|
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '2.0'
|
62
|
-
type: :
|
62
|
+
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
@@ -76,17 +76,22 @@ files:
|
|
76
76
|
- README.md
|
77
77
|
- lib/generators/jsonapi/swagger/USAGE
|
78
78
|
- lib/generators/jsonapi/swagger/swagger_generator.rb
|
79
|
+
- lib/generators/jsonapi/swagger/templates/swagger.json.erb
|
79
80
|
- lib/generators/jsonapi/swagger/templates/swagger.rb.erb
|
80
81
|
- lib/i18n/en.yml
|
81
82
|
- lib/i18n/zh-CN.yml
|
82
83
|
- lib/jsonapi/swagger.rb
|
84
|
+
- lib/jsonapi/swagger/json.rb
|
83
85
|
- lib/jsonapi/swagger/railtie.rb
|
86
|
+
- lib/jsonapi/swagger/resource.rb
|
87
|
+
- lib/jsonapi/swagger/resources/fast_jsonapi_resource.rb
|
88
|
+
- lib/jsonapi/swagger/resources/jsonapi_resource.rb
|
89
|
+
- lib/jsonapi/swagger/resources/serializable_resource.rb
|
84
90
|
- lib/jsonapi/swagger/version.rb
|
85
91
|
homepage: https://github.com/superiorlu/jsonapi-swagger
|
86
92
|
licenses:
|
87
93
|
- MIT
|
88
|
-
metadata:
|
89
|
-
allowed_push_host: https://rubygems.org
|
94
|
+
metadata: {}
|
90
95
|
post_install_message:
|
91
96
|
rdoc_options: []
|
92
97
|
require_paths:
|
@@ -102,7 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
102
107
|
- !ruby/object:Gem::Version
|
103
108
|
version: '0'
|
104
109
|
requirements: []
|
105
|
-
rubygems_version: 3.0.
|
110
|
+
rubygems_version: 3.0.3
|
106
111
|
signing_key:
|
107
112
|
specification_version: 4
|
108
113
|
summary: JSON API Swagger Doc Generator
|