fsdk-2237-ruby-e2e 0.1.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.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +107 -0
  3. data/lib/petstore/client.rb +45 -0
  4. data/lib/petstore/config.rb +54 -0
  5. data/lib/petstore/environment.rb +7 -0
  6. data/lib/petstore/error.rb +40 -0
  7. data/lib/petstore/errors/api_error.rb +9 -0
  8. data/lib/petstore/errors/client_error.rb +43 -0
  9. data/lib/petstore/errors/connection_error.rb +11 -0
  10. data/lib/petstore/errors/redirect_error.rb +9 -0
  11. data/lib/petstore/errors/response_error.rb +92 -0
  12. data/lib/petstore/errors/server_error.rb +25 -0
  13. data/lib/petstore/errors/timeout_error.rb +9 -0
  14. data/lib/petstore/http/auth.rb +19 -0
  15. data/lib/petstore/http/oauth_token_manager.rb +91 -0
  16. data/lib/petstore/internal/errors/constraint_error.rb +10 -0
  17. data/lib/petstore/internal/errors/type_error.rb +10 -0
  18. data/lib/petstore/internal/form/request.rb +110 -0
  19. data/lib/petstore/internal/http/base_request.rb +64 -0
  20. data/lib/petstore/internal/http/event_stream.rb +106 -0
  21. data/lib/petstore/internal/http/raw_client.rb +426 -0
  22. data/lib/petstore/internal/http/response_body.rb +35 -0
  23. data/lib/petstore/internal/iterators/cursor_item_iterator.rb +28 -0
  24. data/lib/petstore/internal/iterators/cursor_page_iterator.rb +72 -0
  25. data/lib/petstore/internal/iterators/item_iterator.rb +72 -0
  26. data/lib/petstore/internal/iterators/offset_item_iterator.rb +30 -0
  27. data/lib/petstore/internal/iterators/offset_page_iterator.rb +110 -0
  28. data/lib/petstore/internal/json/request.rb +61 -0
  29. data/lib/petstore/internal/json/serializable.rb +25 -0
  30. data/lib/petstore/internal/multipart/multipart_encoder.rb +141 -0
  31. data/lib/petstore/internal/multipart/multipart_form_data.rb +78 -0
  32. data/lib/petstore/internal/multipart/multipart_form_data_part.rb +51 -0
  33. data/lib/petstore/internal/multipart/multipart_request.rb +49 -0
  34. data/lib/petstore/internal/raw/request.rb +88 -0
  35. data/lib/petstore/internal/types/array.rb +47 -0
  36. data/lib/petstore/internal/types/boolean.rb +34 -0
  37. data/lib/petstore/internal/types/enum.rb +56 -0
  38. data/lib/petstore/internal/types/hash.rb +36 -0
  39. data/lib/petstore/internal/types/model/field.rb +38 -0
  40. data/lib/petstore/internal/types/model.rb +246 -0
  41. data/lib/petstore/internal/types/type.rb +35 -0
  42. data/lib/petstore/internal/types/union.rb +193 -0
  43. data/lib/petstore/internal/types/unknown.rb +15 -0
  44. data/lib/petstore/internal/types/utils.rb +137 -0
  45. data/lib/petstore/models/open_model.rb +30 -0
  46. data/lib/petstore/models/serializable.rb +63 -0
  47. data/lib/petstore/models/union_type.rb +12 -0
  48. data/lib/petstore/pet/client.rb +196 -0
  49. data/lib/petstore/pet/types/delete_pet_request.rb +13 -0
  50. data/lib/petstore/pet/types/find_pets_by_status_request.rb +11 -0
  51. data/lib/petstore/pet/types/find_pets_by_status_request_status.rb +24 -0
  52. data/lib/petstore/pet/types/find_pets_by_tags_request.rb +11 -0
  53. data/lib/petstore/pet/types/get_pet_by_id_request.rb +11 -0
  54. data/lib/petstore/pet/types/pet.rb +25 -0
  55. data/lib/petstore/pet/types/update_pet_with_form_request.rb +15 -0
  56. data/lib/petstore/serializers/form_serializer.rb +41 -0
  57. data/lib/petstore/serializers/json_serializer.rb +41 -0
  58. data/lib/petstore/serializers/xml_serializer.rb +56 -0
  59. data/lib/petstore/store/client.rb +89 -0
  60. data/lib/petstore/store/types/delete_order_request.rb +11 -0
  61. data/lib/petstore/store/types/get_order_by_id_request.rb +11 -0
  62. data/lib/petstore/store/types/order.rb +25 -0
  63. data/lib/petstore/types/api_response.rb +20 -0
  64. data/lib/petstore/types/category.rb +19 -0
  65. data/lib/petstore/types/order_status.rb +22 -0
  66. data/lib/petstore/types/pet_status.rb +22 -0
  67. data/lib/petstore/types/tag.rb +19 -0
  68. data/lib/petstore/user/client.rb +149 -0
  69. data/lib/petstore/user/types/delete_user_request.rb +11 -0
  70. data/lib/petstore/user/types/get_user_by_name_request.rb +11 -0
  71. data/lib/petstore/user/types/login_user_request.rb +13 -0
  72. data/lib/petstore/user/types/user.rb +27 -0
  73. data/lib/petstore/validator.rb +42 -0
  74. data/lib/petstore/version.rb +5 -0
  75. data/lib/petstore.rb +78 -0
  76. metadata +236 -0
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cgi'
4
+
5
+ module Petstore
6
+ module Internal
7
+ module Types
8
+ # Utilities for dealing with and checking types
9
+ module Utils
10
+ # Wraps a type into a type function
11
+ #
12
+ # @param type [Proc, Object]
13
+ # @return [Proc]
14
+ def self.wrap_type(type)
15
+ case type
16
+ when Proc
17
+ type
18
+ else
19
+ -> { type }
20
+ end
21
+ end
22
+
23
+ # Resolves a type or type function into a type
24
+ #
25
+ # @param type [Proc, Object]
26
+ # @return [Object]
27
+ def self.unwrap_type(type)
28
+ type.is_a?(Proc) ? type.call : type
29
+ end
30
+
31
+ def self.coerce(target, value, strict: false)
32
+ type = unwrap_type(target)
33
+
34
+ case type
35
+ in Array
36
+ case value
37
+ when ::Array
38
+ return type.coerce(value, strict: strict)
39
+ when Set, ::Hash
40
+ return coerce(type, value.to_a)
41
+ end
42
+ in Hash
43
+ case value
44
+ when ::Hash
45
+ return type.coerce(value, strict: strict)
46
+ when ::Array
47
+ return coerce(type, value.to_h)
48
+ end
49
+ in ->(t) { t <= NilClass }
50
+ return nil
51
+ in ->(t) { t <= String }
52
+ case value
53
+ when String, Symbol, Numeric, TrueClass, FalseClass
54
+ return value.to_s
55
+ end
56
+ in ->(t) { t <= Symbol }
57
+ case value
58
+ when Symbol, String
59
+ return value.to_sym
60
+ end
61
+ in ->(t) { t <= Integer }
62
+ case value
63
+ when Numeric, String, Time
64
+ return value.to_i
65
+ end
66
+ in ->(t) { t <= Float }
67
+ case value
68
+ when Numeric, Time, String
69
+ return value.to_f
70
+ end
71
+ in ->(t) { t <= Model }
72
+ case value
73
+ when type
74
+ return value
75
+ when ::Hash
76
+ return type.coerce(value, strict: strict)
77
+ end
78
+ in Module
79
+ case type
80
+ in ->(t) {
81
+ t.singleton_class.include?(Enum) ||
82
+ t.singleton_class.include?(Union)
83
+ }
84
+ return type.coerce(value, strict: strict)
85
+ else
86
+ value # rubocop:disable Lint/Void
87
+ end
88
+ else
89
+ value # rubocop:disable Lint/Void
90
+ end
91
+
92
+ raise Errors::TypeError, "cannot coerce value of type `#{value.class}` to `#{target}`" if strict
93
+
94
+ value
95
+ end
96
+
97
+ def self.symbolize_keys(hash)
98
+ hash.transform_keys(&:to_sym)
99
+ end
100
+
101
+ # Converts camelCase keys to snake_case symbols
102
+ # This allows SDK methods to accept both snake_case and camelCase keys
103
+ # e.g., { refundMethod: ... } becomes { refund_method: ... }
104
+ #
105
+ # @param hash [Hash]
106
+ # @return [Hash]
107
+ # Serializes a header parameter using OpenAPI "simple" style (RFC 6570 section 3.2.2),
108
+ # which is the default for `in: header`. `to_s` alone is wrong for anything but a
109
+ # primitive: an array would reach the wire as Ruby's inspect form (`["a", "b"]`) and a
110
+ # hash as `{"k" => "v"}`, neither of which a server can parse.
111
+ def self.simple_param(value)
112
+ case value
113
+ when nil then nil
114
+ when ::Array then value.map { |v| v.nil? ? '' : v.to_s }.join(',')
115
+ when ::Hash then value.flat_map { |k, v| [k.to_s, v.to_s] }.join(',')
116
+ else value.to_s
117
+ end
118
+ end
119
+
120
+ # Serializes a cookie parameter value. Percent-encoded because `;` and `,` are delimiters
121
+ # in a Cookie header, so an unencoded value can inject additional cookies.
122
+ def self.cookie_param(value)
123
+ ::CGI.escape(simple_param(value).to_s)
124
+ end
125
+
126
+ def self.normalize_keys(hash)
127
+ hash.transform_keys do |key|
128
+ key_str = key.to_s
129
+ # Convert camelCase to snake_case
130
+ snake_case = key_str.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase
131
+ snake_case.to_sym
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Petstore
4
+ module Models
5
+ # Marker module for open object models (additionalProperties: true).
6
+ #
7
+ # Including classes must implement:
8
+ # - #open_model_extras → Hash of extra key/value pairs captured from deserialization
9
+ #
10
+ # In return, this module overrides +#to_h+ to merge the extras into the
11
+ # symbol-keyed hash produced by +Serializable#to_h+, so round-trips through
12
+ # JSON preserve unknown fields without requiring schema changes.
13
+ #
14
+ # +#to_h+ is a symbol-keyed Ruby view: declared fields keep their attribute names and win
15
+ # on collision. +Serializers::Json.serialize+ is the wire-faithful path (keeps raw wire
16
+ # keys) and is what guarantees the unknown-field round-trip.
17
+ module OpenModel
18
+ def open_model_extras
19
+ raise NotImplementedError, "#{self.class} must implement #open_model_extras"
20
+ end
21
+
22
+ def to_h
23
+ extras = open_model_extras
24
+ return super if extras.nil? || extras.empty?
25
+
26
+ extras.transform_keys(&:to_sym).merge(super)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Petstore
4
+ module Models
5
+ # Sentinel value for model fields that were never explicitly set.
6
+ # Distinguishes "field not provided" from "field explicitly set to nil",
7
+ # which matters for PATCH requests where nil means "clear this field".
8
+ UNSET = Object.new.tap do |o|
9
+ o.define_singleton_method(:inspect) { 'UNSET' }
10
+ o.define_singleton_method(:to_s) { 'UNSET' }
11
+ end.freeze
12
+
13
+ # Marker module for generated model classes.
14
+ #
15
+ # Including classes must implement:
16
+ # - .wire_keys → { attr_sym: 'wire_name', ... }.freeze
17
+ # - .from_hash(hash) → model instance or nil
18
+ # - #attributes → { attr_sym: raw_value, ... }
19
+ #
20
+ # In return, this module provides:
21
+ # - #to_h → { attr_sym: value, ... } with nested models recursively converted,
22
+ # omitting fields set to UNSET but preserving explicit nil
23
+ module Serializable
24
+ def self.included(base)
25
+ base.extend(ClassMethods)
26
+ end
27
+
28
+ module ClassMethods
29
+ def wire_keys
30
+ raise NotImplementedError, "#{name} must implement .wire_keys"
31
+ end
32
+
33
+ def from_hash(_hash)
34
+ raise NotImplementedError, "#{name} must implement .from_hash"
35
+ end
36
+ end
37
+
38
+ def to_h
39
+ self.class.wire_keys.each_with_object({}) do |(attr, _key), hash|
40
+ val = attributes[attr]
41
+ next if val.equal?(UNSET)
42
+
43
+ hash[attr] = coerce_to_h(val)
44
+ end
45
+ end
46
+
47
+ def attributes
48
+ raise NotImplementedError, "#{self.class} must implement #attributes"
49
+ end
50
+
51
+ private
52
+
53
+ def coerce_to_h(val)
54
+ return val.to_h if val.is_a?(Serializable)
55
+ return val.map { |item| coerce_to_h(item) } if val.is_a?(Array)
56
+ # Typed maps (additionalProperties): recurse values, preserving the dynamic string keys.
57
+ return val.transform_values { |item| coerce_to_h(item) } if val.is_a?(Hash)
58
+
59
+ val
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Petstore
4
+ module Models
5
+ # Marker module for oneOf/anyOf union wrapper classes.
6
+ #
7
+ # Including classes hold one typed variant in +#value+.
8
+ # Serializers check for this module to delegate serialization to the wrapped value.
9
+ module UnionType
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,196 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uri'
4
+
5
+ module Petstore
6
+ module Pet
7
+ class Client
8
+ def initialize(client:)
9
+ @client = client
10
+ end
11
+
12
+ def add_pet(request_options: {}, **params)
13
+ params = ::Petstore::Internal::Types::Utils.normalize_keys(params)
14
+ request_body = ::Petstore::Pet::Types::Pet.new(params)
15
+ request_body.validate! if request_body.respond_to?(:validate!)
16
+ request = ::Petstore::Internal::JSON::Request.new(
17
+ base_url: request_options[:base_url],
18
+ method: 'POST',
19
+ path: 'pet',
20
+ body: request_body.to_h,
21
+ request_options: request_options,
22
+ )
23
+ response = @client.send(request)
24
+ code = response.code.to_i
25
+ if code.between?(200, 299)
26
+ result = ::Petstore::Internal::Http::ResponseBody.decode(response) { |body| ::Petstore::Pet::Types::Pet.load(body) }
27
+ result.validate! if result.respond_to?(:validate!)
28
+ result
29
+ else
30
+ error_class = ::Petstore::Errors::ResponseError.subclass_for_code(code)
31
+ raise error_class.new(response.body, code: code)
32
+ end
33
+ end
34
+
35
+ def update_pet(request_options: {}, **params)
36
+ params = ::Petstore::Internal::Types::Utils.normalize_keys(params)
37
+ request_body = ::Petstore::Pet::Types::Pet.new(params)
38
+ request_body.validate! if request_body.respond_to?(:validate!)
39
+ request = ::Petstore::Internal::JSON::Request.new(
40
+ base_url: request_options[:base_url],
41
+ method: 'PUT',
42
+ path: 'pet',
43
+ body: request_body.to_h,
44
+ request_options: request_options,
45
+ )
46
+ response = @client.send(request)
47
+ code = response.code.to_i
48
+ if code.between?(200, 299)
49
+ result = ::Petstore::Internal::Http::ResponseBody.decode(response) { |body| ::Petstore::Pet::Types::Pet.load(body) }
50
+ result.validate! if result.respond_to?(:validate!)
51
+ result
52
+ else
53
+ error_class = ::Petstore::Errors::ResponseError.subclass_for_code(code)
54
+ raise error_class.new(response.body, code: code)
55
+ end
56
+ end
57
+
58
+ def find_pets_by_status(request_options: {}, **params)
59
+ params = ::Petstore::Internal::Types::Utils.normalize_keys(params)
60
+ query_params = {}
61
+ query_params['status'] = params[:status] if params.key?(:status)
62
+ request = ::Petstore::Internal::JSON::Request.new(
63
+ base_url: request_options[:base_url],
64
+ method: 'GET',
65
+ path: 'pet/findByStatus',
66
+ query: query_params,
67
+ request_options: request_options,
68
+ )
69
+ response = @client.send(request)
70
+ code = response.code.to_i
71
+ if code.between?(200, 299)
72
+ result = ::Petstore::Internal::Http::ResponseBody.decode(response) { |body| ::Petstore::Internal::Types::Array[::Petstore::Pet::Types::Pet].coerce(::JSON.parse(body, symbolize_names: false)) }
73
+ result&.each { |item| item.validate! if item.respond_to?(:validate!) }
74
+ result
75
+ else
76
+ error_class = ::Petstore::Errors::ResponseError.subclass_for_code(code)
77
+ raise error_class.new(response.body, code: code)
78
+ end
79
+ end
80
+
81
+ def find_pets_by_tags(request_options: {}, **params)
82
+ params = ::Petstore::Internal::Types::Utils.normalize_keys(params)
83
+ query_params = {}
84
+ query_params['tags'] = params[:tags] if params.key?(:tags)
85
+ request = ::Petstore::Internal::JSON::Request.new(
86
+ base_url: request_options[:base_url],
87
+ method: 'GET',
88
+ path: 'pet/findByTags',
89
+ query: query_params,
90
+ request_options: request_options,
91
+ )
92
+ response = @client.send(request)
93
+ code = response.code.to_i
94
+ if code.between?(200, 299)
95
+ result = ::Petstore::Internal::Http::ResponseBody.decode(response) { |body| ::Petstore::Internal::Types::Array[::Petstore::Pet::Types::Pet].coerce(::JSON.parse(body, symbolize_names: false)) }
96
+ result&.each { |item| item.validate! if item.respond_to?(:validate!) }
97
+ result
98
+ else
99
+ error_class = ::Petstore::Errors::ResponseError.subclass_for_code(code)
100
+ raise error_class.new(response.body, code: code)
101
+ end
102
+ end
103
+
104
+ def get_pet_by_id(request_options: {}, **params)
105
+ params = ::Petstore::Internal::Types::Utils.normalize_keys(params)
106
+ request = ::Petstore::Internal::JSON::Request.new(
107
+ base_url: request_options[:base_url],
108
+ method: 'GET',
109
+ path: "pet/#{URI.encode_uri_component(params[:pet_id].to_s)}",
110
+ request_options: request_options,
111
+ )
112
+ response = @client.send(request)
113
+ code = response.code.to_i
114
+ if code.between?(200, 299)
115
+ result = ::Petstore::Internal::Http::ResponseBody.decode(response) { |body| ::Petstore::Pet::Types::Pet.load(body) }
116
+ result.validate! if result.respond_to?(:validate!)
117
+ result
118
+ else
119
+ error_class = ::Petstore::Errors::ResponseError.subclass_for_code(code)
120
+ raise error_class.new(response.body, code: code)
121
+ end
122
+ end
123
+
124
+ def update_pet_with_form(request_options: {}, **params)
125
+ params = ::Petstore::Internal::Types::Utils.normalize_keys(params)
126
+ query_params = {}
127
+ query_params['name'] = params[:name] if params.key?(:name)
128
+ query_params['status'] = params[:status] if params.key?(:status)
129
+ request = ::Petstore::Internal::JSON::Request.new(
130
+ base_url: request_options[:base_url],
131
+ method: 'POST',
132
+ path: "pet/#{URI.encode_uri_component(params[:pet_id].to_s)}",
133
+ query: query_params,
134
+ request_options: request_options,
135
+ )
136
+ response = @client.send(request)
137
+ code = response.code.to_i
138
+ if code.between?(200, 299)
139
+ result = ::Petstore::Internal::Http::ResponseBody.decode(response) { |body| ::Petstore::Pet::Types::Pet.load(body) }
140
+ result.validate! if result.respond_to?(:validate!)
141
+ result
142
+ else
143
+ error_class = ::Petstore::Errors::ResponseError.subclass_for_code(code)
144
+ raise error_class.new(response.body, code: code)
145
+ end
146
+ end
147
+
148
+ def delete_pet(request_options: {}, **params)
149
+ params = ::Petstore::Internal::Types::Utils.normalize_keys(params)
150
+ headers = {}
151
+ headers['api_key'] = ::Petstore::Internal::Types::Utils.simple_param(params[:api_key]) if params.key?(:api_key)
152
+ request = ::Petstore::Internal::JSON::Request.new(
153
+ base_url: request_options[:base_url],
154
+ method: 'DELETE',
155
+ path: "pet/#{URI.encode_uri_component(params[:pet_id].to_s)}",
156
+ headers: headers,
157
+ request_options: request_options,
158
+ )
159
+ response = @client.send(request)
160
+ code = response.code.to_i
161
+ return if code.between?(200, 299)
162
+
163
+ error_class = ::Petstore::Errors::ResponseError.subclass_for_code(code)
164
+ raise error_class.new(response.body, code: code)
165
+ end
166
+
167
+ # @param body [String, #read] The request body, sent verbatim as `application/octet-stream`.
168
+ # Pass it as the `body:` keyword; it is not read from a request model.
169
+ def upload_file(request_options: {}, **params)
170
+ params = ::Petstore::Internal::Types::Utils.normalize_keys(params)
171
+ query_params = {}
172
+ query_params['additionalMetadata'] = params[:additional_metadata] if params.key?(:additional_metadata)
173
+ request = ::Petstore::Internal::Raw::Request.new(
174
+ base_url: request_options[:base_url],
175
+ method: 'POST',
176
+ path: "pet/#{URI.encode_uri_component(params[:pet_id].to_s)}/uploadImage",
177
+ query: query_params,
178
+ body: params[:body],
179
+ content_type: 'application/octet-stream',
180
+ accept: 'application/json',
181
+ request_options: request_options,
182
+ )
183
+ response = @client.send(request)
184
+ code = response.code.to_i
185
+ if code.between?(200, 299)
186
+ result = ::Petstore::Internal::Http::ResponseBody.decode(response) { |body| ::Petstore::Types::APIResponse.load(body) }
187
+ result.validate! if result.respond_to?(:validate!)
188
+ result
189
+ else
190
+ error_class = ::Petstore::Errors::ResponseError.subclass_for_code(code)
191
+ raise error_class.new(response.body, code: code)
192
+ end
193
+ end
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Petstore
4
+ module Pet
5
+ module Types
6
+ class DeletePetRequest < ::Petstore::Internal::Types::Model
7
+ field :pet_id, -> { Integer }, optional: false, nullable: false, api_name: 'petId'
8
+
9
+ field :api_key, -> { String }, optional: true, nullable: false
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Petstore
4
+ module Pet
5
+ module Types
6
+ class FindPetsByStatusRequest < ::Petstore::Internal::Types::Model
7
+ field :status, -> { ::Petstore::Pet::Types::FindPetsByStatusRequestStatus }, optional: false, nullable: false
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Petstore
4
+ module Pet
5
+ module Types
6
+ module FindPetsByStatusRequestStatus
7
+ extend ::Petstore::Internal::Types::Enum
8
+
9
+ AVAILABLE = :available
10
+ PENDING = :pending
11
+ SOLD = :sold
12
+
13
+ def self.load(str)
14
+ coerce(::JSON.parse(str, symbolize_names: true))
15
+ end
16
+
17
+ def self.dump(value)
18
+ coerced = coerce(value)
19
+ ::JSON.generate(coerced.nil? || !coerced.respond_to?(:to_h) ? coerced : coerced.to_h)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Petstore
4
+ module Pet
5
+ module Types
6
+ class FindPetsByTagsRequest < ::Petstore::Internal::Types::Model
7
+ field :tags, -> { ::Petstore::Internal::Types::Array[String] }, optional: false, nullable: false
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Petstore
4
+ module Pet
5
+ module Types
6
+ class GetPetByIDRequest < ::Petstore::Internal::Types::Model
7
+ field :pet_id, -> { Integer }, optional: false, nullable: false, api_name: 'petId'
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Petstore
4
+ module Pet
5
+ module Types
6
+ class Pet < ::Petstore::Internal::Types::Model
7
+ field :id, -> { Integer }, optional: true, nullable: false
8
+ field :name, -> { String }, optional: false, nullable: false
9
+ field :category, -> { ::Petstore::Types::Category }, optional: true, nullable: false
10
+ field :photo_urls, -> { ::Petstore::Internal::Types::Array[String] }, optional: false, nullable: false, api_name: 'photoUrls'
11
+ field :tags, -> { ::Petstore::Internal::Types::Array[::Petstore::Types::Tag] }, optional: true, nullable: false
12
+ field :status, -> { ::Petstore::Types::PetStatus }, optional: true, nullable: false
13
+
14
+ def self.load(str)
15
+ coerce(::JSON.parse(str, symbolize_names: true))
16
+ end
17
+
18
+ def self.dump(value)
19
+ coerced = coerce(value)
20
+ ::JSON.generate(coerced.nil? || !coerced.respond_to?(:to_h) ? coerced : coerced.to_h)
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Petstore
4
+ module Pet
5
+ module Types
6
+ class UpdatePetWithFormRequest < ::Petstore::Internal::Types::Model
7
+ field :pet_id, -> { Integer }, optional: false, nullable: false, api_name: 'petId'
8
+
9
+ field :name, -> { String }, optional: true, nullable: false
10
+
11
+ field :status, -> { String }, optional: true, nullable: false
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'uri'
4
+
5
+ module Petstore
6
+ module Serializers
7
+ # Serializes models or hashes to form-encoded and multipart bodies.
8
+ module Form
9
+ # Encodes a model or hash as application/x-www-form-urlencoded.
10
+ def self.to_urlencoded(value)
11
+ URI.encode_www_form(flatten(value))
12
+ end
13
+
14
+ # Configures a Net::HTTP request for multipart/form-data.
15
+ def self.set_multipart(request, value)
16
+ request.set_form(
17
+ flatten(value).map { |k, v| [k.to_s, v.to_s] },
18
+ 'multipart/form-data',
19
+ )
20
+ end
21
+
22
+ private_class_method def self.flatten(value)
23
+ value = value.value if value.is_a?(Models::UnionType)
24
+ if value.is_a?(Models::Serializable)
25
+ declared = value.class.wire_keys.filter_map do |attr, key|
26
+ val = value.attributes[attr]
27
+ # Form encoding cannot represent null; both UNSET and explicit nil are omitted.
28
+ # Unlike JSON (which serializes nil as null), form bodies have no null concept.
29
+ [key, val] unless val.nil? || val.equal?(Models::UNSET)
30
+ end
31
+ extras = value.is_a?(Models::OpenModel) ? value.open_model_extras.compact.to_a : []
32
+ declared + extras
33
+ elsif value.is_a?(Hash)
34
+ value.compact.to_a
35
+ else
36
+ [['body', value.to_s]]
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Petstore
6
+ module Serializers
7
+ # Serializes models to JSON-ready hashes and deserializes hashes back to models.
8
+ module Json
9
+ # Converts a model, array, or primitive to a plain Ruby hash/value
10
+ # suitable for JSON.generate / .to_json.
11
+ def self.serialize(value)
12
+ return value.map { |item| serialize(item) } if value.is_a?(Array)
13
+ # Typed maps (additionalProperties): serialize values, keeping the dynamic string keys.
14
+ return value.transform_values { |item| serialize(item) } if value.is_a?(Hash)
15
+ return serialize(value.value) if value.is_a?(Models::UnionType)
16
+ return serialize_model(value) if value.is_a?(Models::Serializable)
17
+
18
+ value
19
+ end
20
+
21
+ # Builds a model instance from a plain hash (already JSON.parsed).
22
+ # Returns the raw data unchanged when no model class is provided.
23
+ def self.deserialize(data, model_class = nil)
24
+ return data unless model_class
25
+
26
+ model_class.from_hash(data)
27
+ end
28
+
29
+ private_class_method def self.serialize_model(model)
30
+ result = model.class.wire_keys.each_with_object({}) do |(attr, key), hash|
31
+ val = model.attributes[attr]
32
+ next if val.equal?(Models::UNSET)
33
+
34
+ hash[key] = serialize(val)
35
+ end
36
+ model.open_model_extras.each { |k, v| result[k] = serialize(v) unless result.key?(k) } if model.is_a?(Models::OpenModel)
37
+ result
38
+ end
39
+ end
40
+ end
41
+ end