rest_framework 0.11.0 → 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: 34653421f170160fbdd29c3119c728ba5fe7591fd969f9d50d2e20d18cecf8bb
4
- data.tar.gz: ed35098916c941a897087d9b455f69e86f5f53b1e81442e22aa135c81877c45c
3
+ metadata.gz: acc3d4ff5a9d7669942f21eb7f3ecec06417c83322be936e1b862b1346e9bb14
4
+ data.tar.gz: 53ddfa6b5a46338b174ec67742d6019d5d005231eb492b0af30ed7232a2d22ce
5
5
  SHA512:
6
- metadata.gz: b02af4cc8f15d804a8ece266a3678a5a0ae328cf505aa64478f4239392a2ccc1ddbcbdde333fc8d80c9ba8fbb59d2a057c8fed6150fe0758f068c7c3dca3670c
7
- data.tar.gz: 33d87fa722fa5d0a23ccfd81ea6d5705cc37b49bb9b88ab62f504c76255429c77d0c75b2d83a8f86c3752c6fc7c9a60f3fa9078daebfca5461929d052f43d45f
6
+ metadata.gz: a93ccb739766ae11c9b0be6b52e60c698c72793cd109c1efbaf89eaac3f10b56a7bf11fd9e90b77ccc7c148aaa8436e51f73530f3ed3442f58ee93934fa37494
7
+ data.tar.gz: 616ebaac8b55a68a38fc8d29f6cedf764403990bc057bf9f6d8c92e672764a4f23189a3acca1e803b1d34df70731d28729744380cc90e9b7ec49f133c258d0de
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.11.0
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|
@@ -349,9 +382,9 @@ module RESTFramework::Mixins::BaseModelControllerMixin
349
382
  model = self.class.get_model
350
383
 
351
384
  if model.method(action).parameters.last&.first == :keyrest
352
- return render_api(model.send(action, **params))
385
+ render_api(model.send(action, **params))
353
386
  else
354
- return render_api(model.send(action))
387
+ render_api(model.send(action))
355
388
  end
356
389
  end
357
390
  end
@@ -365,9 +398,9 @@ module RESTFramework::Mixins::BaseModelControllerMixin
365
398
  record = self.get_record
366
399
 
367
400
  if record.method(action).parameters.last&.first == :keyrest
368
- return render_api(record.send(action, **params))
401
+ render_api(record.send(action, **params))
369
402
  else
370
- return render_api(record.send(action))
403
+ render_api(record.send(action))
371
404
  end
372
405
  end
373
406
  end
@@ -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)
@@ -691,7 +690,7 @@ end
691
690
  # Mixin for listing records.
692
691
  module RESTFramework::Mixins::ListModelMixin
693
692
  def index
694
- return render_api(self.get_index_records)
693
+ render_api(self.get_index_records)
695
694
  end
696
695
 
697
696
  # Get records with both filtering and pagination applied.
@@ -719,14 +718,14 @@ end
719
718
  # Mixin for showing records.
720
719
  module RESTFramework::Mixins::ShowModelMixin
721
720
  def show
722
- return render_api(self.get_record)
721
+ render_api(self.get_record)
723
722
  end
724
723
  end
725
724
 
726
725
  # Mixin for creating records.
727
726
  module RESTFramework::Mixins::CreateModelMixin
728
727
  def create
729
- return render_api(self.create!, status: :created)
728
+ render_api(self.create!, status: :created)
730
729
  end
731
730
 
732
731
  # Perform the `create!` call and return the created record.
@@ -738,7 +737,7 @@ end
738
737
  # Mixin for updating records.
739
738
  module RESTFramework::Mixins::UpdateModelMixin
740
739
  def update
741
- return render_api(self.update!)
740
+ render_api(self.update!)
742
741
  end
743
742
 
744
743
  # Perform the `update!` call and return the updated record.
@@ -753,7 +752,7 @@ end
753
752
  module RESTFramework::Mixins::DestroyModelMixin
754
753
  def destroy
755
754
  self.destroy!
756
- return render_api("")
755
+ render_api("")
757
756
  end
758
757
 
759
758
  # Perform the `destroy!` call and return the destroyed (and frozen) record.
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: 0.11.0
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
@@ -99,9 +99,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
99
99
  version: 2.3.0
100
100
  required_rubygems_version: !ruby/object:Gem::Requirement
101
101
  requirements:
102
- - - ">="
102
+ - - ">"
103
103
  - !ruby/object:Gem::Version
104
- version: '0'
104
+ version: 1.3.1
105
105
  requirements: []
106
106
  rubygems_version: 3.4.10
107
107
  signing_key: