bullet_train-api 1.7.10 → 1.7.11

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: 832c27ca7af794811031cece070f5c19c3a711507a6acc02dee6b50a1ac2a7ca
4
- data.tar.gz: 0a436d84fa41177ab407541f24e8af26afb5d96ae1e9417463a051a012079dc7
3
+ metadata.gz: aef8c20ab58036263c4aedee16b5957f9794f6db67388b88f308ad2de6eddcd2
4
+ data.tar.gz: c97837332c5bf099547093477248223dd5efecc9dfe6327b10e27173bff8b981
5
5
  SHA512:
6
- metadata.gz: f5dd7ddc3e438803826251511d350708a7c9cc909c5633bd0e0da8352dc8c3571f5a4bfe2f2408906d2a01afb210bc5dfc0d14c49c25a641b4c286e3eda71051
7
- data.tar.gz: a4d3b63282da9b6081c546754d6f9bb6fc2f6d490e5b1b5bfd087f1806774d2720c69c8c1d1dfb6ac49d1c293e10225b1b398b00f6ca9fbf31656ae49ae940f1
6
+ metadata.gz: f7b9c1c254e7425b2a5a48b1badf2a6b22667b4724e761291ee4a577bd048b3bfe3663864eb0a34bf653d54a4c741f044f1d6ac7a44e8b8d581e6303f082f6dc
7
+ data.tar.gz: 81ff21bf84669a24a2972fcc6b6441661c18e3074b31f1c94945572b4e34dfe4923ef21985b3adaa5e1c5bdc70353d82567853e1da03f49da8c22a2053eeda55
data/README.md CHANGED
@@ -20,6 +20,7 @@ Then, run `bundle` or install it manually using `gem install bullet_train-api`.
20
20
  - [Documentation](#documentation)
21
21
  - [Index file](#index-file)
22
22
  - [Automatic Components](#automatic-components)
23
+ - [Manually Extending Component Schemas](#manually-extending-component-schemas)
23
24
  - [Automatic Paths](#automatic-paths)
24
25
  - [External Markdown files](#external-markdown-files)
25
26
  - [Examples](#examples)
@@ -144,6 +145,59 @@ As you can see, it automatically sets required fields based on presence validato
144
145
  field types based on the value found in Jbuilder file, descriptions and examples.
145
146
  More on how it works and how you can customize the output in [`jbuilder-schema`](https://github.com/bullet-train-co/jbuilder-schema) documentation.
146
147
 
148
+ #### Manually Extending Component Schemas
149
+
150
+ While `automatic_components_for` automatically adds parameters and attributes from your application, sometimes it is
151
+ necessary to manually specify parameters and attributes in addition to the automatic ones, due to custom code in
152
+ your app.
153
+
154
+ `automatic_components_for` allows to you add or remove parameters and attributes. You can also specify that
155
+ parameters that are only available for create or update methods.
156
+
157
+ ##### Adding or Removing Specific Attributes for a Component
158
+
159
+ To add or remove specific attributes for a component:
160
+
161
+ automatic_components_for User,
162
+ parameters: {
163
+ add: {
164
+ tag_ids: {
165
+ type: :array,
166
+ items: {type: :integer},
167
+ description: "Array of Tag IDs for the User."
168
+ }
169
+ }
170
+ },
171
+ attributes: {
172
+ remove: [:email, :time_zone],
173
+ add: {
174
+ url: {
175
+ type: :string,
176
+ description: "The URL of the User's image."
177
+ }
178
+ }
179
+ }
180
+
181
+ ##### Specifying Parameters for Create or Update Methods
182
+
183
+ To specify parameters that only exist for the create or update methods, use the following format:
184
+
185
+ automatic_components_for Enrollment,
186
+ parameters: {
187
+ create: {
188
+ add: {
189
+ user_id: {
190
+ type: :integer,
191
+ description: "ID of the User who enrolled.",
192
+ example: 42
193
+ }
194
+ }
195
+ },
196
+ update: {
197
+ remove: [:time_zone]
198
+ }
199
+ }
200
+
147
201
  #### Automatic Paths
148
202
 
149
203
  Method `automatic_paths_for` generates basic REST paths. It accepts model as it's argument.
@@ -155,7 +209,7 @@ a write action (i.e. create or update), then doc generation uses the `strong_par
155
209
  defined in the corresponding controller to generate the Parameters section in the schema.
156
210
 
157
211
  Automatic paths are generated for basic REST actions. You can customize those paths or add your own by creating a
158
- file at `app/views/api/<version>/open_api/<Model.underscore.plural>/_paths.yaml.erb`. For REST paths there's no need to
212
+ file at `app/views/api/<version>/open_api/<Model.underscore.plural>/_paths.yaml.erb`. For REST paths there's no need to
159
213
  duplicate all the schema, you can specify only what differs from auto-generated code.
160
214
 
161
215
  #### External Markdown files
@@ -100,24 +100,24 @@ module Api
100
100
  end
101
101
 
102
102
  if has_strong_parameters?("Api::#{@version.upcase}::#{model.name.pluralize}Controller".constantize)
103
- strong_params_module = "Api::#{@version.upcase}::#{model.name.pluralize}Controller::StrongParameters".constantize
104
- strong_parameter_keys = BulletTrain::Api::StrongParametersReporter.new(model, strong_params_module).report
105
- if strong_parameter_keys.last.is_a?(Hash)
106
- strong_parameter_keys += strong_parameter_keys.pop.keys
103
+ strong_parameter_keys = strong_parameter_keys_for(model.name, @version)
104
+
105
+ # Create separate parameter schema for create and update methods
106
+ create_parameters_output = process_strong_parameters(model, strong_parameter_keys, schema_json, "create", **options)
107
+ update_parameters_output = process_strong_parameters(model, strong_parameter_keys, schema_json, "update", **options)
108
+
109
+ # We need to skip TeamParameters, UserParameters & InvitationParametersUpdate as they are not present in
110
+ # the bullet train api schema
111
+ if model.name == "Team" || model.name == "User"
112
+ create_parameters_output = nil
113
+ elsif model.name == "Invitation"
114
+ update_parameters_output = nil
107
115
  end
108
116
 
109
- parameters_output = JSON.parse(schema_json)
110
- parameters_output["required"].select! { |key| strong_parameter_keys.include?(key.to_sym) }
111
- parameters_output["properties"].select! { |key| strong_parameter_keys.include?(key.to_sym) }
112
- parameters_output["example"]&.select! { |key, value| strong_parameter_keys.include?(key.to_sym) && value.present? }
113
-
114
- # Allow customization of Parameters
115
- customize_component!(parameters_output, options[:parameters]) if options[:parameters]
116
-
117
- (
118
- indent(attributes_output.to_yaml.gsub("---", "#{model.name.gsub("::", "")}Attributes:"), 3) +
119
- indent(" " + parameters_output.to_yaml.gsub("---", "#{model.name.gsub("::", "")}Parameters:"), 3)
120
- ).html_safe
117
+ output = indent(attributes_output.to_yaml.gsub("---", "#{model.name.gsub("::", "")}Attributes:"), 3)
118
+ output += indent(" " + create_parameters_output.to_yaml.gsub("---", "#{model.name.gsub("::", "")}Parameters:"), 3) if create_parameters_output
119
+ output += indent(" " + update_parameters_output.to_yaml.gsub("---", "#{model.name.gsub("::", "")}ParametersUpdate:"), 3) if update_parameters_output
120
+ output.html_safe
121
121
  else
122
122
 
123
123
  indent(attributes_output.to_yaml.gsub("---", "#{model.name.gsub("::", "")}Attributes:"), 3)
@@ -125,6 +125,37 @@ module Api
125
125
  end
126
126
  end
127
127
 
128
+ def process_strong_parameters(model, strong_parameter_keys, schema_json, method_type, **options)
129
+ parameters_output = JSON.parse(schema_json)
130
+ parameters_output["required"].select! { |key| strong_parameter_keys.include?(key.to_sym) }
131
+ parameters_output["properties"].select! { |key| strong_parameter_keys.include?(key.to_sym) }
132
+ parameters_output["example"]&.select! { |key, value| strong_parameter_keys.include?(key.to_sym) }
133
+
134
+ # Allow customization of Parameters
135
+ parameters_custom = options[:parameters][method_type] if options[:parameters].is_a?(Hash) && options[:parameters].key?(method_type)
136
+ parameters_custom ||= options[:parameters]
137
+ customize_component!(parameters_output, parameters_custom, method_type) if parameters_custom
138
+
139
+ # We need to wrap the example parameters with the model name as expected by the API controllers
140
+ if parameters_output["example"]
141
+ parameters_output["example"] = {model.model_name.param_key => parameters_output["example"]}
142
+ end
143
+
144
+ parameters_output
145
+ end
146
+
147
+ def strong_parameter_keys_for(model_name, version)
148
+ strong_params_module = "::Api::#{version.upcase}::#{model_name.pluralize}Controller::StrongParameters".constantize
149
+ strong_params_reporter = BulletTrain::Api::StrongParametersReporter.new(model_name.constantize, strong_params_module)
150
+ strong_parameter_keys = strong_params_reporter.report
151
+
152
+ if strong_parameter_keys.last.is_a?(Hash)
153
+ strong_parameter_keys += strong_parameter_keys.pop.keys
154
+ end
155
+
156
+ strong_parameter_keys
157
+ end
158
+
128
159
  def paths_for(model)
129
160
  for_model model do
130
161
  indent(render("api/#{@version}/open_api/#{model.name.underscore.pluralize}/paths"), 1)
@@ -154,9 +185,9 @@ module Api
154
185
  methods.include?("create") || methods.include?("update")
155
186
  end
156
187
 
157
- def update_ref_values!(hash)
188
+ def update_ref_values!(hash, method_type = nil)
158
189
  hash.each do |key, value|
159
- if key == "$ref" && value.is_a?(String) && !value.include?("Attributes")
190
+ if key == "$ref" && value.is_a?(String) && !value.include?("Attributes#{method_type.to_s.camelize}")
160
191
  # Extract the part after "#/components/schemas/"
161
192
  schema_part = value.split("#/components/schemas/").last
162
193
 
@@ -164,14 +195,14 @@ module Api
164
195
  camelized_schema = schema_part.split("/").map(&:camelize).join
165
196
 
166
197
  # Update the value
167
- hash[key] = "#/components/schemas/#{camelized_schema}Attributes"
198
+ hash[key] = "#/components/schemas/#{camelized_schema}Attributes#{method_type.to_s.camelize}"
168
199
  elsif value.is_a?(Hash)
169
200
  # Recursively call the method for nested hashes
170
- update_ref_values!(value)
201
+ update_ref_values!(value, method_type)
171
202
  elsif value.is_a?(Array)
172
203
  # Recursively call the method for each hash in the array
173
204
  value.each do |item|
174
- update_ref_values!(item) if item.is_a?(Hash)
205
+ update_ref_values!(item, method_type) if item.is_a?(Hash)
175
206
  end
176
207
  end
177
208
  end
@@ -189,9 +220,25 @@ module Api
189
220
  end
190
221
  end
191
222
 
192
- def customize_component!(original, custom)
223
+ # This allows for customization of the attribute and parameter components.
224
+ #
225
+ # General customizations for all methods:
226
+ # automatic_components_for User,
227
+ # attributes: {remove: [:email, :time_zone]}, parameters: {add: {email: {type: :string, required: true, example: "fred@example.com"}}
228
+ # automatic_components_for User,
229
+ # attributes: {remove: [:email, :time_zone]}, parameters: {remove: [:email, :time_zone, :locale]}
230
+ # Or specific customizations to parameters for create and update methods:
231
+ # automatic_components_for User,
232
+ # parameters: {update: {remove: [:email]}, create: {remove: [:time_zone]}},
233
+ # attributes: {remove: [:email, :time_zone]}
234
+ def customize_component!(original, custom, method_type = nil)
193
235
  custom = custom.deep_stringify_keys.deep_transform_values { |v| v.is_a?(Symbol) ? v.to_s : v }
194
236
 
237
+ # Check if customizations are provided for specific HTTP methods
238
+ if custom.key?(method_type.to_s)
239
+ custom = custom[method_type.to_s]
240
+ end
241
+
195
242
  if custom.key?("add")
196
243
  custom["add"].each do |property, details|
197
244
  if details["required"]
@@ -59,7 +59,7 @@
59
59
  type: object
60
60
  $ref: "#/components/schemas/ScaffoldingCompletelyConcreteTangibleThingParameters"
61
61
  example:
62
- 🚅 post_parameters
62
+ $ref: "#/components/schemas/ScaffoldingCompletelyConcreteTangibleThingParameters/example"
63
63
  responses:
64
64
  "404":
65
65
  description: "Not Found"
@@ -115,9 +115,9 @@
115
115
  properties:
116
116
  scaffolding_completely_concrete_tangible_thing:
117
117
  type: object
118
- $ref: "#/components/schemas/ScaffoldingCompletelyConcreteTangibleThingParameters"
118
+ $ref: "#/components/schemas/ScaffoldingCompletelyConcreteTangibleThingParametersUpdate"
119
119
  example:
120
- 🚅 put_parameters
120
+ $ref: "#/components/schemas/ScaffoldingCompletelyConcreteTangibleThingParametersUpdate/example"
121
121
  responses:
122
122
  "404":
123
123
  description: "Not Found"
@@ -64,7 +64,7 @@
64
64
  properties:
65
65
  team:
66
66
  type: object
67
- $ref: "#/components/schemas/TeamParameters"
67
+ $ref: "#/components/schemas/TeamParametersUpdate"
68
68
  example:
69
69
  <%= FactoryBot.put_parameters(:team, version: @version) %>
70
70
  responses:
@@ -63,7 +63,7 @@
63
63
  properties:
64
64
  user:
65
65
  type: object
66
- $ref: "#/components/schemas/UserParameters"
66
+ $ref: "#/components/schemas/UserParametersUpdate"
67
67
  example:
68
68
  <%= FactoryBot.put_parameters(:user, version: @version) %>
69
69
  responses:
@@ -43,11 +43,7 @@ module FactoryBot
43
43
 
44
44
  if method.end_with?("parameters")
45
45
  if has_strong_parameters?("::Api::#{version.upcase}::#{class_name.pluralize}Controller".constantize)
46
- strong_params_module = "::Api::#{version.upcase}::#{class_name.pluralize}Controller::StrongParameters".constantize
47
- strong_parameter_keys = BulletTrain::Api::StrongParametersReporter.new(class_name.constantize, strong_params_module).report
48
- if strong_parameter_keys.last.is_a?(Hash)
49
- strong_parameter_keys += strong_parameter_keys.pop.keys
50
- end
46
+ strong_parameter_keys = strong_parameter_keys_for(class_name, version)
51
47
 
52
48
  output = _json_output(template, version, class_name, var_name, values)
53
49
 
@@ -41,8 +41,16 @@ module BulletTrain
41
41
  # end
42
42
  # end
43
43
 
44
- def report
45
- @filters = send(:"#{@model.name.split("::").last.underscore}_params")
44
+ def report(method_type = nil)
45
+ method_type = ["create", "update"].include?(method_type) ? method_type : nil
46
+ base_method_name = @model.name.split("::").last.underscore
47
+
48
+ # if available in the controller, it will use the 'update' strong params instead of the default strong params.
49
+ @filters = if method_type == "update" && respond_to?("#{base_method_name}_#{method_type}_params".to_sym, true)
50
+ send(:"#{base_method_name}_#{method_type}_params")
51
+ else
52
+ send(:"#{base_method_name}_params")
53
+ end
46
54
 
47
55
  # There's a reason I'm doing it this way.
48
56
  @filters
@@ -1,5 +1,5 @@
1
1
  module BulletTrain
2
2
  module Api
3
- VERSION = "1.7.10"
3
+ VERSION = "1.7.11"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bullet_train-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.10
4
+ version: 1.7.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Culver
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-05-30 00:00:00.000000000 Z
11
+ date: 2024-06-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: standard