jsonapi-swagger 0.5.0 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
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