taro 2.1.0 → 2.3.0

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: c4f35df13466f65caaf120945539ca21fcd2562dc3e79145817c66f75f58c016
4
- data.tar.gz: c3f2af6555b7a3c9f6e81a6ba69f5fceea0663ed6b93c22cfe584f478a2a4b24
3
+ metadata.gz: c96d6fd71ad22df31d5ab4cefb09389fd7ed5b41b5dd8821132fa2c5fa322837
4
+ data.tar.gz: f56362229e93f2f8c51a5490245d4a37e224015fecd42bb86a35926a01e8d776
5
5
  SHA512:
6
- metadata.gz: c3c7de4bb79a0f78f1060ea32bf65e1da9bf597f09790d95f5c0e09a0fdc175de973aebdc28c39a1aa994dbd0fd41e6be3097508ddfad57474ad774603aac933
7
- data.tar.gz: aad75b1177ff07d1e95415e720076d85734de7ebd185e2503e4fa80fdf8ffba4e2f2cf4df735582ed6e69599cfba413ce901abcd043f178efcf1ec6ef9072054
6
+ metadata.gz: 34ad2aedee3c3a21973420ca5e1185024c7d6b127ee9ca914b847134939bcd136e70f10130607b8392ce8044dfcb7c8014fa306d00d81b81266d68fcdad19b95
7
+ data.tar.gz: 1bec2fbada3a23267f87195323b2b112297c21e78c22281071bd2ec84a7359f78836ed250e85ae3f3d1765f428dd7ff1bdaaf92f5df2bd17883abed11b7a39eb
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [2.3.0] - 2025-02-24
4
+
5
+ ### Added
6
+
7
+ - `Taro.config.raise_for_undeclared_params`
8
+
9
+ ## [2.2.0] - 2025-02-22
10
+
11
+ ### Added
12
+
13
+ - error message when incorrectly chaining `with_cache`
14
+
3
15
  ## [2.1.0] - 2025-02-21
4
16
 
5
17
  ### Added
data/README.md CHANGED
@@ -140,6 +140,14 @@ Requests are automatically validated to match the declared input schema, unless
140
140
  Taro.config.parse_params = false
141
141
  ```
142
142
 
143
+ There is also an option to raise an error if any undeclared params are submitted:
144
+
145
+ ```ruby
146
+ Taro.config.raise_for_undeclared_params = true
147
+ ```
148
+
149
+ This option is similar to `action_on_unpermitted_parameters = :raise` in Rails and is most useful in dev and test environments. The railtie enables it automatically in these environments.
150
+
143
151
  #### Response validation
144
152
 
145
153
  Responses are automatically validated to have used the correct type for rendering, which guarantees that they match the declaration. This means you have to use the types to render complex responses, and manually building a Hash that conforms to the schema will raise an error. Primitive/scalar types are an exception, e.g. you *can* do:
@@ -244,6 +252,27 @@ class ErrorType < ObjectType
244
252
  end
245
253
  ```
246
254
 
255
+ ### Caching
256
+
257
+ Taro provides support for caching. The cache instance can be configured by setting `Taro::Cache.cache_instance`. By default, the railtie will set it to `Rails.cache`.
258
+
259
+ It supports configuring an ad hoc cache when using a render call, e.g.
260
+
261
+ ```ruby
262
+ bike = Bike.find(params[:id])
263
+ BikeType.with_cache(cache_key: bike.cache_key, expires_in: 3.minutes).render(bike)
264
+ ```
265
+
266
+ Or by configuring the cache rule on a per type basis, e.g.
267
+
268
+ ```ruby
269
+ class BikeType < ObjectType
270
+ self.cache_key = ->(bike) { bike.cache_key_with_version }
271
+ self.expires_in = 1.hour
272
+ # ...
273
+ end
274
+ ```
275
+
247
276
  ## FAQ
248
277
 
249
278
  ### How do I render API docs?
@@ -344,33 +373,8 @@ class MyController < ApplicationController
344
373
  end
345
374
  ```
346
375
 
347
- ## Caching
348
-
349
- Taro provides support for caching. The cache instance can be configured by setting `Taro::Cache.cache_instance`. By default, the railtie will set it to `Rails.cache`.
350
-
351
- It supports configuring an add hoc cache when using a render call, e.g.
352
-
353
- ```ruby
354
- bike = Bike.find(params[:id])
355
- BikeType.with_cache(cache_key: bike.cache_key, expires_in: 3.minutes).render(bike)
356
- ```
357
-
358
- Or by configuring the cache rule on a per type bases, e.g.
359
-
360
- ```ruby
361
- class BikeType < ObjectType
362
- # Optional description of BikeType (for the OpenAPI export)
363
- self.desc = 'A bike and all relevant information about it'
364
- self.cache_key = ->(bike) { bike.cache_key_with_version }
365
- self.expires_in = 1.hour
366
-
367
- ...
368
- end
369
- ```
370
-
371
376
  ## Possible future features
372
377
 
373
- - warning/raising for undeclared input params (currently they are ignored)
374
378
  - usage without rails is possible but not convenient yet
375
379
  - rspec matchers for testing
376
380
  - sum types
data/lib/taro/config.rb CHANGED
@@ -5,6 +5,7 @@ module Taro::Config
5
5
  :export_format,
6
6
  :export_path,
7
7
  :parse_params,
8
+ :raise_for_undeclared_params,
8
9
  :validate_response,
9
10
  )
10
11
 
@@ -14,6 +15,7 @@ module Taro::Config
14
15
  self.export_format = :yaml
15
16
  self.export_path = 'api.yml'
16
17
  self.parse_params = true
18
+ self.raise_for_undeclared_params = false # may be overridden by railtie
17
19
  self.validate_response = true
18
20
  end
19
21
 
@@ -5,7 +5,7 @@ class Taro::Declaration
5
5
  attr_reader :desc, :summary, :params, :return_defs, :return_descriptions, :tags
6
6
 
7
7
  def initialize(for_klass = nil)
8
- @params = Class.new(Taro::Types::InputType)
8
+ @params = Class.new(Taro::Types::RailsParamsType)
9
9
  @return_defs = {}
10
10
  @return_descriptions = {}
11
11
 
@@ -1,5 +1,7 @@
1
1
  class Taro::Rails::Railtie < ::Rails::Railtie
2
2
  initializer("taro") do |app|
3
+ Taro.config.raise_for_undeclared_params = %w[development test].include?(Rails.env)
4
+
3
5
  # The `:action_controller` hook fires for both ActionController::API
4
6
  # and ActionController::Base, executing the block in their context.
5
7
  ActiveSupport.on_load(:action_controller) do
@@ -22,4 +22,5 @@ Taro::Types::BaseType = Struct.new(:object) do
22
22
  extend Taro::Types::Shared::Rendering
23
23
  include Taro::Types::Shared::Caching
24
24
  include Taro::Types::Shared::Errors
25
+ include Taro::Types::Shared::TypeClass
25
26
  end
@@ -3,6 +3,7 @@ require_relative 'field_validation'
3
3
  Taro::Types::Field = Data.define(:name, :type, :null, :method, :default, :enum, :defined_at, :desc, :deprecated) do
4
4
  include Taro::Types::FieldValidation
5
5
  include Taro::Types::Shared::Errors
6
+ include Taro::Types::Shared::TypeClass
6
7
 
7
8
  def initialize(name:, type:, null:, method: name, default: Taro::None, enum: nil, defined_at: nil, desc: nil, deprecated: nil)
8
9
  enum = coerce_to_enum(enum)
@@ -0,0 +1,10 @@
1
+ require_relative 'object_type'
2
+
3
+ # Abstract base class for rails declaration params. Internal use only.
4
+ class Taro::Types::RailsParamsType < Taro::Types::InputType
5
+ # Skip validation of base params because they contain rails "additions"
6
+ # like controller, action, routing-related stuff, de-nested values, etc.
7
+ def validate_no_undeclared_params?
8
+ false
9
+ end
10
+ end
@@ -7,7 +7,7 @@ module Taro::Types::Shared::Caching
7
7
 
8
8
  def self.included(klass)
9
9
  klass.extend(ClassMethods)
10
- klass.singleton_class.attr_accessor :expires_in, :without_cache
10
+ klass.singleton_class.attr_accessor :expires_in
11
11
  klass.singleton_class.attr_reader :cache_key
12
12
  end
13
13
 
@@ -23,7 +23,8 @@ module Taro::Types::Shared::Caching
23
23
  klass = dup
24
24
  klass.cache_key = cache_key.is_a?(Proc) ? cache_key : ->(_) { cache_key }
25
25
  klass.expires_in = expires_in
26
- klass.without_cache = self
26
+ this = self
27
+ klass.define_singleton_method(:type_class) { this }
27
28
  klass
28
29
  end
29
30
  end
@@ -35,9 +35,11 @@ module Taro::Types::Shared::DerivedTypes
35
35
 
36
36
  root.define_singleton_method(method_name) do
37
37
  derived_types[type] ||= begin
38
- type_class = Taro::Types::Coercion.call(type:)
39
- new_type = Class.new(type_class)
40
- new_type.define_name("#{self.name}.#{method_name}")
38
+ name || raise(Taro::ArgumentError, 'Cannot derive from anonymous type')
39
+
40
+ coerced_type = Taro::Types::Coercion.call(type:)
41
+ new_type = Class.new(coerced_type)
42
+ new_type.define_name("#{name}.#{method_name}")
41
43
  new_type.derive_from(self)
42
44
  new_type
43
45
  end
@@ -1,6 +1,7 @@
1
1
  # Provides input and response handling for types with fields.
2
2
  module Taro::Types::Shared::ObjectCoercion
3
3
  def coerce_input
4
+ validate_no_undeclared_params
4
5
  self.class.fields.transform_values do |field|
5
6
  field.value_for_input(object)
6
7
  end
@@ -13,4 +14,17 @@ module Taro::Types::Shared::ObjectCoercion
13
14
  field.value_for_response(object, context: self, object_is_hash:)
14
15
  end
15
16
  end
17
+
18
+ private
19
+
20
+ def validate_no_undeclared_params
21
+ return unless validate_no_undeclared_params?
22
+
23
+ undeclared = object.to_h.keys.map(&:to_sym) - self.class.send(:field_defs).keys
24
+ undeclared.any? && input_error("Undeclared params: #{undeclared.join(', ')}")
25
+ end
26
+
27
+ def validate_no_undeclared_params?
28
+ Taro.config.raise_for_undeclared_params
29
+ end
16
30
  end
@@ -1,11 +1,9 @@
1
1
  module Taro::Types::Shared::Rendering
2
2
  # The `::render` method is intended for use in controllers.
3
3
  # Overrides of this method must call super.
4
- def render(object, cache_attrs = {})
5
- result = Taro::Cache.call(object, **cache_attrs) do
6
- new(object).cached_coerce_response
7
- end
8
- self.last_render = [self.without_cache || self, result.__id__]
4
+ def render(object)
5
+ result = new(object).cached_coerce_response
6
+ self.last_render = [type_class, result.__id__]
9
7
  result
10
8
  end
11
9
 
@@ -0,0 +1,12 @@
1
+ # `type_class` is a convenience method to get the type class of types,
2
+ # of with_cache-types, of type instances, and of fields in the same way.
3
+ module Taro::Types::Shared::TypeClass
4
+ def self.included(klass)
5
+ if klass.instance_methods.include?(:type) # Field
6
+ klass.alias_method :type_class, :type
7
+ else # BaseType
8
+ klass.singleton_class.alias_method :type_class, :itself
9
+ klass.alias_method :type_class, :class
10
+ end
11
+ end
12
+ end
data/lib/taro/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  # :nocov:
2
2
  module Taro
3
- VERSION = "2.1.0"
3
+ VERSION = "2.3.0"
4
4
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: taro
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Janosch Müller
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2025-02-21 00:00:00.000000000 Z
12
+ date: 2025-02-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -89,6 +89,7 @@ files:
89
89
  - lib/taro/types/object_types/no_content_type.rb
90
90
  - lib/taro/types/object_types/page_info_type.rb
91
91
  - lib/taro/types/object_types/page_type.rb
92
+ - lib/taro/types/rails_params_type.rb
92
93
  - lib/taro/types/response_type.rb
93
94
  - lib/taro/types/scalar/boolean_type.rb
94
95
  - lib/taro/types/scalar/float_type.rb
@@ -117,6 +118,7 @@ files:
117
118
  - lib/taro/types/shared/openapi_type.rb
118
119
  - lib/taro/types/shared/pattern.rb
119
120
  - lib/taro/types/shared/rendering.rb
121
+ - lib/taro/types/shared/type_class.rb
120
122
  - lib/taro/version.rb
121
123
  - tasks/benchmark.rake
122
124
  - tasks/benchmark_1kb.json
@@ -143,7 +145,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
143
145
  - !ruby/object:Gem::Version
144
146
  version: '0'
145
147
  requirements: []
146
- rubygems_version: 3.5.16
148
+ rubygems_version: 3.5.22
147
149
  signing_key:
148
150
  specification_version: 4
149
151
  summary: Typed Api using Ruby Objects.