rest_framework 1.0.0.beta1 → 1.0.0.beta2

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: 4261d5bdf6f4e59ffce35b2a5f36bafe104bddd9b9437f34b77b495acbeefac6
4
- data.tar.gz: 84f0213bfd2d54777059049b87b84f2ff4c727c45838c130ec7382b5d1aa451c
3
+ metadata.gz: acc3d4ff5a9d7669942f21eb7f3ecec06417c83322be936e1b862b1346e9bb14
4
+ data.tar.gz: 53ddfa6b5a46338b174ec67742d6019d5d005231eb492b0af30ed7232a2d22ce
5
5
  SHA512:
6
- metadata.gz: 2d2308561ba8ae8668f2e3fd83da4487d1b9ba3b4ca632c1be21fe6bfbf5cb88b8f0a661624dc97a837473263ae944a1231ef7c8b90284d8851b275780326886
7
- data.tar.gz: 030d5acc028ae343486c30968c66b25ab91d5577a48f236ccf4766ee8675b75c1f83ca8cb3f442dd9a0be93209142acd1aa4ba7d5cfd7c318521bbdc91cb986b
6
+ metadata.gz: a93ccb739766ae11c9b0be6b52e60c698c72793cd109c1efbaf89eaac3f10b56a7bf11fd9e90b77ccc7c148aaa8436e51f73530f3ed3442f58ee93934fa37494
7
+ data.tar.gz: 616ebaac8b55a68a38fc8d29f6cedf764403990bc057bf9f6d8c92e672764a4f23189a3acca1e803b1d34df70731d28729744380cc90e9b7ec49f133c258d0de
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.0.beta1
1
+ 1.0.0.beta2
@@ -12,6 +12,7 @@ module RESTFramework::Mixins::BaseControllerMixin
12
12
  description: nil,
13
13
  version: nil,
14
14
  inflect_acronyms: ["ID", "IDs", "REST", "API", "APIs"].freeze,
15
+ openapi_include_children: false,
15
16
 
16
17
  # Options related to serialization.
17
18
  rescue_unknown_format_with: :json,
@@ -69,6 +70,82 @@ module RESTFramework::Mixins::BaseControllerMixin
69
70
  end
70
71
  end
71
72
  # :nocov:
73
+
74
+ def openapi_paths(routes, tag)
75
+ response_content_types = [
76
+ "text/html",
77
+ self.serialize_to_json ? "application/json" : nil,
78
+ self.serialize_to_xml ? "application/xml" : nil,
79
+ ].compact
80
+ request_content_types = [
81
+ "application/json",
82
+ "application/xml",
83
+ "application/x-www-form-urlencoded",
84
+ "multipart/form-data",
85
+ ]
86
+
87
+ return routes.group_by { |r| r[:concat_path] }.map { |concat_path, routes|
88
+ [
89
+ concat_path.gsub(/:([0-9A-Za-z_-]+)/, "{\\1}"),
90
+ routes.map { |route|
91
+ metadata = route[:route].defaults[:metadata] || {}
92
+ summary = metadata[:label].presence || self.label_for(route[:action])
93
+ description = metadata[:description].presence
94
+ remaining_metadata = metadata.except(:label, :description).presence
95
+
96
+ [
97
+ route[:verb].downcase,
98
+ {
99
+ tags: [tag],
100
+ summary: summary,
101
+ description: description,
102
+ responses: {
103
+ 200 => {
104
+ content: response_content_types.map { |ct|
105
+ [ct, {}]
106
+ }.to_h,
107
+ description: "",
108
+ },
109
+ },
110
+ requestBody: route[:verb].in?(["GET", "DELETE", "OPTIONS", "TRACE"]) ? nil : {
111
+ content: request_content_types.map { |ct|
112
+ [ct, {}]
113
+ }.to_h,
114
+ },
115
+ "x-rrf-metadata": remaining_metadata,
116
+ }.compact,
117
+ ]
118
+ }.to_h.merge(
119
+ {
120
+ parameters: routes.first[:route].required_parts.map { |p|
121
+ {
122
+ name: p,
123
+ in: "path",
124
+ required: true,
125
+ schema: {type: "integer"},
126
+ }
127
+ },
128
+ },
129
+ ),
130
+ ]
131
+ }.to_h
132
+ end
133
+
134
+ def openapi_document(request, route_group_name, routes)
135
+ server = request.base_url + request.original_fullpath.gsub(/\?.*/, "")
136
+
137
+ return {
138
+ openapi: "3.1.1",
139
+ info: {
140
+ title: self.get_title,
141
+ description: self.description,
142
+ version: self.version.to_s,
143
+ }.compact,
144
+ servers: [{url: server}],
145
+ paths: self.openapi_paths(routes, route_group_name),
146
+ tags: [{name: route_group_name, description: self.description}.compact],
147
+ }.compact
148
+ end
72
149
  end
73
150
 
74
151
  def self.included(base)
@@ -239,81 +316,36 @@ module RESTFramework::Mixins::BaseControllerMixin
239
316
  end
240
317
  end
241
318
 
242
- # TODO: Might make this the default render method in the future.
319
+ # Compatibility alias for deprecated `api_response`.
243
320
  alias_method :api_response, :render_api
244
321
 
245
- def openapi_metadata
246
- response_content_types = [
247
- "text/html",
248
- self.class.serialize_to_json ? "application/json" : nil,
249
- self.class.serialize_to_xml ? "application/xml" : nil,
250
- ].compact
251
- request_content_types = [
252
- "application/json",
253
- "application/xml",
254
- "application/x-www-form-urlencoded",
255
- "multipart/form-data",
256
- ].compact
257
- routes = self.route_groups.values[0]
258
- server = request.base_url + request.original_fullpath.gsub(/\?.*/, "")
259
-
260
- return {
261
- openapi: "3.1.1",
262
- info: {
263
- title: self.class.get_title,
264
- description: self.class.description,
265
- version: self.class.version.to_s,
266
- }.compact,
267
- servers: [{url: server}],
268
- paths: routes.group_by { |r| r[:concat_path] }.map { |concat_path, routes|
269
- [
270
- concat_path.gsub(/:([0-9A-Za-z_-]+)/, "{\\1}"),
271
- routes.map { |route|
272
- metadata = route[:route].defaults[:metadata] || {}
273
- summary = metadata[:label].presence || self.class.label_for(route[:action])
274
- description = metadata[:description].presence
275
- remaining_metadata = metadata.except(:label, :description).presence
322
+ def openapi_document
323
+ first, *rest = self.route_groups.to_a
324
+ document = self.class.openapi_document(request, *first)
276
325
 
277
- [
278
- route[:verb].downcase,
279
- {
280
- summary: summary,
281
- description: description,
282
- responses: {
283
- 200 => {
284
- content: response_content_types.map { |ct|
285
- [ct, {}]
286
- }.to_h,
287
- description: "",
288
- },
289
- },
290
- requestBody: route[:verb].in?(["GET", "DELETE", "OPTIONS", "TRACE"]) ? nil : {
291
- content: request_content_types.map { |ct|
292
- [ct, {}]
293
- }.to_h,
294
- },
295
- "x-rrf-metadata": remaining_metadata,
296
- }.compact,
297
- ]
298
- }.to_h.merge(
299
- {
300
- parameters: routes.first[:route].required_parts.map { |p|
301
- {
302
- name: p,
303
- in: "path",
304
- required: true,
305
- schema: {type: "integer"},
306
- }
307
- },
308
- },
309
- ),
310
- ]
311
- }.to_h,
312
- }.compact
326
+ if self.class.openapi_include_children
327
+ rest.each do |route_group_name, routes|
328
+ controller = "#{routes.first[:route].defaults[:controller]}_controller".camelize.constantize
329
+ child_document = controller.openapi_document(request, route_group_name, routes)
330
+
331
+ # Merge child paths and tags into the parent document.
332
+ document[:paths].merge!(child_document[:paths])
333
+ document[:tags] += child_document[:tags]
334
+
335
+ # If the child document has schemas, merge them into the parent document.
336
+ if schemas = child_document.dig(:components, :schemas) # rubocop:disable Style/Next
337
+ document[:components] ||= {}
338
+ document[:components][:schemas] ||= {}
339
+ document[:components][:schemas].merge!(schemas)
340
+ end
341
+ end
342
+ end
343
+
344
+ return document
313
345
  end
314
346
 
315
347
  def options
316
- render_api(self.openapi_metadata)
348
+ render_api(self.openapi_document)
317
349
  end
318
350
  end
319
351
 
@@ -6,7 +6,7 @@ module RESTFramework::Mixins::BulkCreateModelMixin
6
6
  # While bulk update/destroy are obvious because they create new router endpoints, bulk create
7
7
  # overloads the existing collection `POST` endpoint, so we add a special key to the OpenAPI
8
8
  # metadata to indicate bulk create is supported.
9
- def openapi_metadata
9
+ def openapi_document
10
10
  return super.merge({"x-rrf-bulk-create": true})
11
11
  end
12
12
 
@@ -339,6 +339,39 @@ module RESTFramework::Mixins::BaseModelControllerMixin
339
339
  return @openapi_schema
340
340
  end
341
341
 
342
+ def openapi_document(request, route_group_name, routes)
343
+ document = super
344
+ schema_name = routes[0][:controller].camelize.gsub("::", ".")
345
+
346
+ # Insert schema into the document.
347
+ document[:components] ||= {}
348
+ document[:components][:schemas] ||= {}
349
+ document[:components][:schemas][schema_name] = self.openapi_schema
350
+
351
+ # Reference schema for specific actions with a `requestBody`.
352
+ document[:paths].each do |_path, actions|
353
+ actions.each do |_method, action|
354
+ next unless action.is_a?(Hash)
355
+
356
+ injectables = [action.dig(:requestBody, :content), *action[:responses].values.map { |r|
357
+ r[:content]
358
+ }].compact
359
+ injectables.each do |i|
360
+ i.each do |_, v|
361
+ v[:schema] = {"$ref" => "#/components/schemas/#{schema_name}"}
362
+ end
363
+ end
364
+ end
365
+ end
366
+
367
+ return document.merge(
368
+ {
369
+ "x-rrf-primary_key" => self.get_model.primary_key,
370
+ "x-rrf-callbacks" => self._process_action_callbacks.as_json,
371
+ },
372
+ )
373
+ end
374
+
342
375
  def setup_delegation
343
376
  # Delegate extra actions.
344
377
  self.extra_actions&.each do |action, config|
@@ -409,40 +442,6 @@ module RESTFramework::Mixins::BaseModelControllerMixin
409
442
  return self.class.get_fields(input_fields: self.class.fields)
410
443
  end
411
444
 
412
- def openapi_metadata
413
- data = super
414
- routes = self.route_groups.values[0]
415
- schema_name = routes[0][:controller].camelize.gsub("::", ".")
416
-
417
- # Insert schema into metadata.
418
- data[:components] ||= {}
419
- data[:components][:schemas] ||= {}
420
- data[:components][:schemas][schema_name] = self.class.openapi_schema
421
-
422
- # Reference schema for specific actions with a `requestBody`.
423
- data[:paths].each do |_path, actions|
424
- actions.each do |_method, action|
425
- next unless action.is_a?(Hash)
426
-
427
- injectables = [action.dig(:requestBody, :content), *action[:responses].values.map { |r|
428
- r[:content]
429
- }].compact
430
- injectables.each do |i|
431
- i.each do |_, v|
432
- v[:schema] = {"$ref" => "#/components/schemas/#{schema_name}"}
433
- end
434
- end
435
- end
436
- end
437
-
438
- return data.merge(
439
- {
440
- "x-rrf-primary_key" => self.class.get_model.primary_key,
441
- "x-rrf-callbacks" => self._process_action_callbacks.as_json,
442
- },
443
- )
444
- end
445
-
446
445
  # Get a hash of strong parameters for the current action.
447
446
  def get_allowed_parameters
448
447
  return @_get_allowed_parameters if defined?(@_get_allowed_parameters)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rest_framework
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.beta1
4
+ version: 1.0.0.beta2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gregory N. Schmit
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-12-25 00:00:00.000000000 Z
11
+ date: 2024-12-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails