rest_framework 1.0.0.beta1 → 1.0.0.beta2

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: 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