taro 2.3.0 → 2.5.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: c96d6fd71ad22df31d5ab4cefb09389fd7ed5b41b5dd8821132fa2c5fa322837
4
- data.tar.gz: f56362229e93f2f8c51a5490245d4a37e224015fecd42bb86a35926a01e8d776
3
+ metadata.gz: d8f629d8573ed34c2d60303a387e99cae4cc9fcb0b14901d7080def1e27d0d90
4
+ data.tar.gz: 40c3ae606ade65922c5b69f9dd86353f2740d061b6d7094f61abe906e5f9198f
5
5
  SHA512:
6
- metadata.gz: 34ad2aedee3c3a21973420ca5e1185024c7d6b127ee9ca914b847134939bcd136e70f10130607b8392ce8044dfcb7c8014fa306d00d81b81266d68fcdad19b95
7
- data.tar.gz: 1bec2fbada3a23267f87195323b2b112297c21e78c22281071bd2ec84a7359f78836ed250e85ae3f3d1765f428dd7ff1bdaaf92f5df2bd17883abed11b7a39eb
6
+ metadata.gz: 34b8e8d9ef5c2f016f56a887b674fa243ae6074fc59e4d29a1cb1873c4dfc3e87d8c24a37dd93a461ad71fc0fd38849462360bed7f6f9a1cca89e37fb3ad192b
7
+ data.tar.gz: d99f3bdc2e40e555a1a0b54dcac6a62d5774b6ae2c7c0d5e05c5ee0f1457864af696b37949173d8189769b03b5d9ce589eb1f49d855209c5c2bccadf32b51d84
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [2.5.0] - 2025-04-16
4
+
5
+ ### Added
6
+
7
+ - Support for setting `openapi_format` for types and during export
8
+
9
+ ## [2.4.0] - 2025-03-11
10
+
11
+ ### Added
12
+
13
+ - `PageWithTotalCountType` for paginated responses with a total count
14
+
3
15
  ## [2.3.0] - 2025-02-24
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: 'list of bikes'
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
 
@@ -273,6 +270,32 @@ class BikeType < ObjectType
273
270
  end
274
271
  ```
275
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
+
276
299
  ## FAQ
277
300
 
278
301
  ### How do I render API docs?
@@ -343,6 +366,7 @@ Why e.g. `field :id, type: 'UUID'` instead of `field :id, type: UUID`?
343
366
 
344
367
  The purpose of this is to reduce unnecessary autoloading of the whole type dependency tree in dev and test environments.
345
368
 
369
+ <a name="derived-types"></a>
346
370
  ### Can I define my own derived types like `page_of` or `array_of`?
347
371
 
348
372
  Yes.
@@ -386,7 +410,6 @@ end
386
410
  - mixed arrays
387
411
  - mixed enums
388
412
  - nullable enums
389
- - string format specifications (e.g. binary, int64, password ...)
390
413
  - string minLength and maxLength (substitute: `self.pattern = /\A.{3,5}\z/`)
391
414
  - number minimum, exclusiveMinimum, maximum, multipleOf
392
415
  - readOnly, writeOnly
@@ -129,7 +129,7 @@ class Taro::Export::OpenAPIv3 < Taro::Export::Base # rubocop:disable Metrics/Cla
129
129
 
130
130
  def export_type(type)
131
131
  if type < Taro::Types::ScalarType && !custom_scalar_type?(type)
132
- { type: type.openapi_type }
132
+ { type: type.openapi_type, format: type.openapi_format }.compact
133
133
  else
134
134
  extract_component_ref(type)
135
135
  end
@@ -148,7 +148,7 @@ class Taro::Export::OpenAPIv3 < Taro::Export::Base # rubocop:disable Metrics/Cla
148
148
  end
149
149
 
150
150
  def export_scalar_field(field)
151
- base = { type: field.openapi_type }
151
+ base = { type: field.openapi_type, format: field.openapi_format }.compact
152
152
  # Using oneOf seems more correct than an array of types
153
153
  # as it puts props like format together with the main type.
154
154
  # https://github.com/OAI/OpenAPI-Specification/issues/3148
@@ -17,6 +17,7 @@ Taro::Types::BaseType = Struct.new(:object) do
17
17
  extend Taro::Types::Shared::Description
18
18
  extend Taro::Types::Shared::Equivalence
19
19
  extend Taro::Types::Shared::Name
20
+ extend Taro::Types::Shared::OpenAPIFormat
20
21
  extend Taro::Types::Shared::OpenAPIName
21
22
  extend Taro::Types::Shared::OpenAPIType
22
23
  extend Taro::Types::Shared::Rendering
@@ -30,6 +30,10 @@ Taro::Types::Field = Data.define(:name, :type, :null, :method, :default, :enum,
30
30
  type.openapi_type
31
31
  end
32
32
 
33
+ def openapi_format
34
+ type.openapi_format
35
+ end
36
+
33
37
  private
34
38
 
35
39
  def coerce_to_enum(arg)
@@ -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, after:, limit: 20, order_by: nil, order: nil)
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,61 @@
1
+ # Provides a setter and getter for type classes' `openapi_format`,
2
+ # for use in the OpenAPI export.
3
+ module Taro::Types::Shared::OpenAPIFormat
4
+ OPENAPI_STRING_FORMATS = %i[
5
+ date
6
+ date-time
7
+ password
8
+ byte
9
+ binary
10
+ email
11
+ uuid
12
+ uri
13
+ hostname
14
+ ipv4
15
+ ipv6
16
+ ].freeze
17
+
18
+ OPENAPI_INTEGER_FORMATS = %i[
19
+ int32
20
+ int64
21
+ ].freeze
22
+
23
+ OPENAPI_NUMBER_FORMATS = %i[
24
+ float
25
+ double
26
+ ].freeze
27
+
28
+ def openapi_format
29
+ return unless @openapi_format
30
+
31
+ unless valid_formats_for_openapi_type.include?(@openapi_format)
32
+ raise(Taro::ArgumentError, "openapi_format #{@openapi_format.inspect} is invalid for openapi_type #{@openapi_type.inspect}, must be one for #{valid_formats_for_openapi_type}")
33
+ end
34
+
35
+ @openapi_format
36
+ end
37
+
38
+ def openapi_format=(arg)
39
+ @openapi_format = arg
40
+ end
41
+
42
+ def inherited(subclass)
43
+ subclass.instance_variable_set(:@openapi_format, @openapi_format)
44
+ super
45
+ end
46
+
47
+ private
48
+
49
+ def valid_formats_for_openapi_type
50
+ case @openapi_type
51
+ when :string
52
+ OPENAPI_STRING_FORMATS
53
+ when :integer
54
+ OPENAPI_INTEGER_FORMATS
55
+ when :number
56
+ OPENAPI_NUMBER_FORMATS
57
+ else
58
+ []
59
+ end
60
+ end
61
+ end
data/lib/taro/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  # :nocov:
2
2
  module Taro
3
- VERSION = "2.3.0"
3
+ VERSION = "2.5.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.3.0
4
+ version: 2.5.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-24 00:00:00.000000000 Z
12
+ date: 2025-04-16 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/object_types/page_with_total_count_type.rb
92
93
  - lib/taro/types/rails_params_type.rb
93
94
  - lib/taro/types/response_type.rb
94
95
  - lib/taro/types/scalar/boolean_type.rb
@@ -114,6 +115,7 @@ files:
114
115
  - lib/taro/types/shared/item_type.rb
115
116
  - lib/taro/types/shared/name.rb
116
117
  - lib/taro/types/shared/object_coercion.rb
118
+ - lib/taro/types/shared/openapi_format.rb
117
119
  - lib/taro/types/shared/openapi_name.rb
118
120
  - lib/taro/types/shared/openapi_type.rb
119
121
  - lib/taro/types/shared/pattern.rb
@@ -145,7 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
145
147
  - !ruby/object:Gem::Version
146
148
  version: '0'
147
149
  requirements: []
148
- rubygems_version: 3.5.22
150
+ rubygems_version: 3.5.16
149
151
  signing_key:
150
152
  specification_version: 4
151
153
  summary: Typed Api using Ruby Objects.