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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 92c1984cded48de28c42fc2c6cea1942f17a985a485c0620941a55e8a6d8259c
4
- data.tar.gz: 5ecc81a8c945a282346a0f20420be0cd047fcf715abea97986cf374285b780d1
3
+ metadata.gz: dab83649ba5e56cfa51c621a9fb47add67a4a2ae889d44b6ba4b3bc1e712fea8
4
+ data.tar.gz: 94a539114d9f3ae6b0da32f79562e319e75219b354e90266986168507d141fa7
5
5
  SHA512:
6
- metadata.gz: b1918de62437786e214d29396a254693899d34325d3762a20c0327bf8f340b848a36a92ae3815e16b607fbb7b07957e7d2fc7ca3b842b9f991750edcc084f6cc
7
- data.tar.gz: 8f93aa0c863bc241859ca952f2d103346552af40882bbfa35d68900561a832e0af3daf4c131c361e0bced923ccf1d35e3347828fe88565bb23663cc3805ebfde
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
- [![Gem Version](https://img.shields.io/gem/v/jsonapi-swagger.svg)](https://rubygems.org/gems/jsonapi-swagger) [![GitHub license](https://img.shields.io/github/license/superiorlu/jsonapi-swagger.svg)](https://github.com/superiorlu/jsonapi-swagger/blob/master/LICENSE)
5
+ [![Gem Version](https://img.shields.io/gem/v/jsonapi-swagger.svg)](https://rubygems.org/gems/jsonapi-swagger)
6
+ [![GitHub license](https://img.shields.io/github/license/superiorlu/jsonapi-swagger.svg)](https://github.com/superiorlu/jsonapi-swagger/blob/master/LICENSE)
6
7
 
7
8
  [![jsonapi-swagger-4-2-9.gif](https://i.loli.net/2019/05/05/5ccebf5e782b7.gif)](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
- rails generate jsonapi:swagger User # UserResponse < JSONAPI::Resource
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 https://github.com/superiorlu/jsonapi-swagger.
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
- swagger_file = File.join(
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
- private
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
- model_class_name.safe_constantize
85
+ file_name.camelize.safe_constantize
43
86
  end
44
87
 
45
88
  def resource_klass
46
- "#{model_class_name}Resource".safe_constantize
89
+ @resource_klass ||= Jsonapi::Swagger::Resource.with(model_class_name)
47
90
  end
48
91
 
49
92
  def attributes
50
- resource_klass._attributes.except(:id)
93
+ resource_klass.attributes.except(:id)
51
94
  end
52
95
 
53
96
  def relationships
54
- resource_klass._relationships
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 columns_with_comment
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
- clos[col.name.to_sym] = { type: swagger_type(col), items_type: col.type, is_array: col.array, nullable: col.null, comment: safe_encode(col.comment) }
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
- content = I18n.t(key, options)
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.class_name.tableize %>]', in: :query, type: :string, description: '<%= t(:display_field) %>', required: false
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.class_name.tableize %>]', in: :query, type: :string, description: '<%= t(:display_field) %>', required: false
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 resource_klass.mutable? -%>
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: {
@@ -1,6 +1,7 @@
1
1
  en:
2
2
  jsonapi_swagger:
3
3
  page_num: 'Page Number'
4
+ page_size: 'Page Size'
4
5
  include_related_data: 'Include Related Data'
5
6
  sortable_fields: 'Sortable Fields'
6
7
  display_field: 'Display Field'
@@ -1,6 +1,7 @@
1
1
  zh-CN:
2
2
  jsonapi_swagger:
3
3
  page_num: '页码'
4
+ page_size: '每页条数'
4
5
  include_related_data: '包含关联数据'
5
6
  sortable_fields: '排序字段'
6
7
  display_field: '显示字段'
@@ -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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Jsonapi
4
4
  module Swagger
5
- VERSION = '0.5.0'
5
+ VERSION = '0.8.1'
6
6
  end
7
7
  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.5.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: 2019-05-08 00:00:00.000000000 Z
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: '10.0'
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: '10.0'
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: :runtime
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.1
110
+ rubygems_version: 3.0.3
106
111
  signing_key:
107
112
  specification_version: 4
108
113
  summary: JSON API Swagger Doc Generator