taro 2.2.0 → 2.4.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 +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +36 -5
- data/lib/taro/config.rb +2 -0
- data/lib/taro/declaration.rb +1 -1
- data/lib/taro/rails/railtie.rb +2 -0
- data/lib/taro/types/object_types/page_type.rb +6 -4
- data/lib/taro/types/object_types/page_with_total_count_type.rb +26 -0
- data/lib/taro/types/rails_params_type.rb +10 -0
- data/lib/taro/types/shared/object_coercion.rb +14 -0
- data/lib/taro/types/shared/rendering.rb +2 -4
- data/lib/taro/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9c7750f1403fa65519d22915908d5aeb6cf5bbeec5497d68369bf5a4e37fb0e8
|
4
|
+
data.tar.gz: 0b6d6b440c1f4fcdb965af8fb1aaf2d26f2ca3a9d2a2fb924bfe9456cb811090
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1f37ffe80f9f14ef49bd3131f0a64f5254219c4851de19ec6523143d508440cb263741c2ca56858eeff917cf0a4d1002b642b4e6f87498e47b62b3ffc5fbc4c8
|
7
|
+
data.tar.gz: 59fbfef1126825880c2d5b64b1d2a3799c25502d094f9758fa9181d7e1e3fa44b2b2504ccbf24c1d18925a5e53ceef1e1ca309cd8980f8950d385d1f3197aadb
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [2.4.0] - 2025-03-11
|
4
|
+
|
5
|
+
### Added
|
6
|
+
|
7
|
+
- `PageWithTotalCountType` for paginated responses with a total count
|
8
|
+
|
9
|
+
## [2.3.0] - 2025-02-24
|
10
|
+
|
11
|
+
### Added
|
12
|
+
|
13
|
+
- `Taro.config.raise_for_undeclared_params`
|
14
|
+
|
3
15
|
## [2.2.0] - 2025-02-22
|
4
16
|
|
5
17
|
### Added
|
data/README.md
CHANGED
@@ -65,7 +65,7 @@ class BikesController < ApplicationController
|
|
65
65
|
|
66
66
|
# Support for arrays and paginated lists is built-in.
|
67
67
|
api 'List all bikes'
|
68
|
-
returns code: :ok, array_of: 'BikeType', desc: '
|
68
|
+
returns code: :ok, array_of: 'BikeType', desc: 'List of bikes'
|
69
69
|
def index
|
70
70
|
render json: BikeType.array.render(Bike.all)
|
71
71
|
end
|
@@ -89,9 +89,6 @@ class BikeType < ObjectType
|
|
89
89
|
# Fields can reference other types and arrays of values
|
90
90
|
field :users, array_of: 'UserType', null: false
|
91
91
|
|
92
|
-
# Pagination is built-in for big lists
|
93
|
-
field :parts, page_of: 'PartType', null: false
|
94
|
-
|
95
92
|
# Custom methods can be chosen to resolve fields
|
96
93
|
field :has_brand, type: 'Boolean', null: false, method: :brand?
|
97
94
|
|
@@ -140,6 +137,14 @@ Requests are automatically validated to match the declared input schema, unless
|
|
140
137
|
Taro.config.parse_params = false
|
141
138
|
```
|
142
139
|
|
140
|
+
There is also an option to raise an error if any undeclared params are submitted:
|
141
|
+
|
142
|
+
```ruby
|
143
|
+
Taro.config.raise_for_undeclared_params = true
|
144
|
+
```
|
145
|
+
|
146
|
+
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.
|
147
|
+
|
143
148
|
#### Response validation
|
144
149
|
|
145
150
|
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:
|
@@ -265,6 +270,32 @@ class BikeType < ObjectType
|
|
265
270
|
end
|
266
271
|
```
|
267
272
|
|
273
|
+
### Pagination
|
274
|
+
|
275
|
+
Use `page_of:` to declare a paginated response. Call `page.render` on a type to render a page of records.
|
276
|
+
|
277
|
+
```ruby
|
278
|
+
api 'List all bikes'
|
279
|
+
param :cursor, type: 'String', null: true, desc: 'Show bikes after this cursor'
|
280
|
+
returns code: :ok, page_of: 'BikeType', desc: 'A page of bikes'
|
281
|
+
def index
|
282
|
+
render json: BikeType.page.render(Bike.all, after: params[:cursor])
|
283
|
+
end
|
284
|
+
```
|
285
|
+
|
286
|
+
By default, the response does not include a total count. To include it, use `page_with_total_count`:
|
287
|
+
|
288
|
+
```ruby
|
289
|
+
api 'List all bikes'
|
290
|
+
param :cursor, type: 'String', null: true, desc: 'Show bikes after this cursor'
|
291
|
+
returns code: :ok, page_with_total_count_of: 'BikeType', desc: 'A page of bikes'
|
292
|
+
def index
|
293
|
+
render json: BikeType.page_with_total_count.render(Bike.all, after: params[:cursor])
|
294
|
+
end
|
295
|
+
```
|
296
|
+
|
297
|
+
See also: [Derived types](#derived-types).
|
298
|
+
|
268
299
|
## FAQ
|
269
300
|
|
270
301
|
### How do I render API docs?
|
@@ -335,6 +366,7 @@ Why e.g. `field :id, type: 'UUID'` instead of `field :id, type: UUID`?
|
|
335
366
|
|
336
367
|
The purpose of this is to reduce unnecessary autoloading of the whole type dependency tree in dev and test environments.
|
337
368
|
|
369
|
+
<a name="derived-types"></a>
|
338
370
|
### Can I define my own derived types like `page_of` or `array_of`?
|
339
371
|
|
340
372
|
Yes.
|
@@ -367,7 +399,6 @@ end
|
|
367
399
|
|
368
400
|
## Possible future features
|
369
401
|
|
370
|
-
- warning/raising for undeclared input params (currently they are ignored)
|
371
402
|
- usage without rails is possible but not convenient yet
|
372
403
|
- rspec matchers for testing
|
373
404
|
- 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
|
|
data/lib/taro/declaration.rb
CHANGED
@@ -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::
|
8
|
+
@params = Class.new(Taro::Types::RailsParamsType)
|
9
9
|
@return_defs = {}
|
10
10
|
@return_descriptions = {}
|
11
11
|
|
data/lib/taro/rails/railtie.rb
CHANGED
@@ -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
|
@@ -13,14 +13,16 @@ class Taro::Types::ObjectTypes::PageType < Taro::Types::ResponseType
|
|
13
13
|
field(:page_info, type: 'Taro::Types::ObjectTypes::PageInfoType', null: false)
|
14
14
|
end
|
15
15
|
|
16
|
-
def self.render(relation,
|
16
|
+
def self.render(relation, **)
|
17
|
+
super(paginate(relation, **))
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.paginate(relation, after:, limit: 20, order_by: nil, order: nil)
|
17
21
|
result = RailsCursorPagination::Paginator.new(
|
18
22
|
relation, limit:, order_by:, order:, after:
|
19
23
|
).fetch
|
20
|
-
|
21
24
|
result[:page].map! { |el| el.fetch(:data) }
|
22
|
-
|
23
|
-
super(result)
|
25
|
+
result
|
24
26
|
end
|
25
27
|
|
26
28
|
def self.default_openapi_name
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# This is an expanded `PageType` that adds a `total_count` field
|
2
|
+
# to show the total number of records in the paginated relation.
|
3
|
+
# It is not recommended for very large relations where counting might be slow.
|
4
|
+
#
|
5
|
+
# Usage:
|
6
|
+
# - `returns code: :ok, page_with_total_count_of: 'UserType'`
|
7
|
+
# - `UserType.page_with_total_count.render(User.all, after: params[:cursor])`
|
8
|
+
#
|
9
|
+
# The gem rails_cursor_pagination must be installed to use this.
|
10
|
+
#
|
11
|
+
class Taro::Types::ObjectTypes::PageWithTotalCountType < Taro::Types::ObjectTypes::PageType
|
12
|
+
def self.derive_from(from_type)
|
13
|
+
super
|
14
|
+
field(:total_count, type: 'Integer', null: false)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.paginate(relation, **)
|
18
|
+
super.merge(total_count: relation.count)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.default_openapi_name
|
22
|
+
"#{item_type.openapi_name}_PageWithTotalCount"
|
23
|
+
end
|
24
|
+
|
25
|
+
define_derived_type :page_with_total_count, 'Taro::Types::ObjectTypes::PageWithTotalCountType'
|
26
|
+
end
|
@@ -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
|
@@ -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,10 +1,8 @@
|
|
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
|
5
|
-
result =
|
6
|
-
new(object).cached_coerce_response
|
7
|
-
end
|
4
|
+
def render(object)
|
5
|
+
result = new(object).cached_coerce_response
|
8
6
|
self.last_render = [type_class, result.__id__]
|
9
7
|
result
|
10
8
|
end
|
data/lib/taro/version.rb
CHANGED
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.
|
4
|
+
version: 2.4.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-
|
12
|
+
date: 2025-03-11 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rack
|
@@ -89,6 +89,8 @@ 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/object_types/page_with_total_count_type.rb
|
93
|
+
- lib/taro/types/rails_params_type.rb
|
92
94
|
- lib/taro/types/response_type.rb
|
93
95
|
- lib/taro/types/scalar/boolean_type.rb
|
94
96
|
- lib/taro/types/scalar/float_type.rb
|