webscraping_ai 2.0.2 → 3.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,12 +1,12 @@
1
1
  =begin
2
2
  #WebScraping.AI
3
3
 
4
- #A client for https://webscraping.ai API. It provides a web scaping automation API with Chrome JS rendering, rotating proxies and builtin HTML parsing.
4
+ #WebScraping.AI scraping API provides GPT-powered tools with Chromium JavaScript rendering, rotating proxies, and built-in HTML parsing.
5
5
 
6
- The version of the OpenAPI document: 2.0.2
6
+ The version of the OpenAPI document: 3.1.2
7
7
  Contact: support@webscraping.ai
8
8
  Generated by: https://openapi-generator.tech
9
- OpenAPI Generator version: 4.3.1
9
+ OpenAPI Generator version: 7.2.0
10
10
 
11
11
  =end
12
12
 
@@ -14,8 +14,10 @@ require 'date'
14
14
  require 'json'
15
15
  require 'logger'
16
16
  require 'tempfile'
17
+ require 'time'
17
18
  require 'typhoeus'
18
19
 
20
+
19
21
  module WebScrapingAI
20
22
  class ApiClient
21
23
  # The Configuration object holding settings to be used in the API client.
@@ -44,9 +46,10 @@ module WebScrapingAI
44
46
  # Call an API with given options.
45
47
  #
46
48
  # @return [Array<(Object, Integer, Hash)>] an array of 3 elements:
47
- # the data deserialized from response body (could be nil), response status code and response headers.
49
+ # the data deserialized from response body (may be a Tempfile or nil), response status code and response headers.
48
50
  def call_api(http_method, path, opts = {})
49
51
  request = build_request(http_method, path, opts)
52
+ tempfile = download_file(request) if opts[:return_type] == 'File'
50
53
  response = request.run
51
54
 
52
55
  if @config.debugging
@@ -68,7 +71,9 @@ module WebScrapingAI
68
71
  end
69
72
  end
70
73
 
71
- if opts[:return_type]
74
+ if opts[:return_type] == 'File'
75
+ data = tempfile
76
+ elsif opts[:return_type]
72
77
  data = deserialize(response, opts[:return_type])
73
78
  else
74
79
  data = nil
@@ -86,12 +91,13 @@ module WebScrapingAI
86
91
  # @option opts [Object] :body HTTP body (JSON/XML)
87
92
  # @return [Typhoeus::Request] A Typhoeus Request
88
93
  def build_request(http_method, path, opts = {})
89
- url = build_request_url(path)
94
+ url = build_request_url(path, opts)
90
95
  http_method = http_method.to_sym.downcase
91
96
 
92
97
  header_params = @default_headers.merge(opts[:header_params] || {})
93
98
  query_params = opts[:query_params] || {}
94
99
  form_params = opts[:form_params] || {}
100
+ follow_location = opts[:follow_location] || true
95
101
 
96
102
  update_params_for_auth! header_params, query_params, opts[:auth_names]
97
103
 
@@ -108,7 +114,8 @@ module WebScrapingAI
108
114
  :ssl_verifyhost => _verify_ssl_host,
109
115
  :sslcert => @config.cert_file,
110
116
  :sslkey => @config.key_file,
111
- :verbose => @config.debugging
117
+ :verbose => @config.debugging,
118
+ :followlocation => follow_location
112
119
  }
113
120
 
114
121
  # set custom cert, if provided
@@ -122,9 +129,7 @@ module WebScrapingAI
122
129
  end
123
130
  end
124
131
 
125
- request = Typhoeus::Request.new(url, req_opts)
126
- download_file(request) if opts[:return_type] == 'File'
127
- request
132
+ Typhoeus::Request.new(url, req_opts)
128
133
  end
129
134
 
130
135
  # Builds the HTTP request body
@@ -155,6 +160,49 @@ module WebScrapingAI
155
160
  data
156
161
  end
157
162
 
163
+ # Save response body into a file in (the defined) temporary folder, using the filename
164
+ # from the "Content-Disposition" header if provided, otherwise a random filename.
165
+ # The response body is written to the file in chunks in order to handle files which
166
+ # size is larger than maximum Ruby String or even larger than the maximum memory a Ruby
167
+ # process can use.
168
+ #
169
+ # @see Configuration#temp_folder_path
170
+ #
171
+ # @return [Tempfile] the tempfile generated
172
+ def download_file(request)
173
+ tempfile = nil
174
+ encoding = nil
175
+ request.on_headers do |response|
176
+ content_disposition = response.headers['Content-Disposition']
177
+ if content_disposition && content_disposition =~ /filename=/i
178
+ filename = content_disposition[/filename=['"]?([^'"\s]+)['"]?/, 1]
179
+ prefix = sanitize_filename(filename)
180
+ else
181
+ prefix = 'download-'
182
+ end
183
+ prefix = prefix + '-' unless prefix.end_with?('-')
184
+ encoding = response.body.encoding
185
+ tempfile = Tempfile.open(prefix, @config.temp_folder_path, encoding: encoding)
186
+ end
187
+ request.on_body do |chunk|
188
+ chunk.force_encoding(encoding)
189
+ tempfile.write(chunk)
190
+ end
191
+ # run the request to ensure the tempfile is created successfully before returning it
192
+ request.run
193
+ if tempfile
194
+ tempfile.close
195
+ @config.logger.info "Temp file written to #{tempfile.path}, please copy the file to a proper folder "\
196
+ "with e.g. `FileUtils.cp(tempfile.path, '/new/file/path')` otherwise the temp file "\
197
+ "will be deleted automatically with GC. It's also recommended to delete the temp file "\
198
+ "explicitly with `tempfile.delete`"
199
+ else
200
+ fail ApiError.new("Failed to create the tempfile based on the HTTP response from the server: #{request.inspect}")
201
+ end
202
+
203
+ tempfile
204
+ end
205
+
158
206
  # Check if the given MIME is a JSON MIME.
159
207
  # JSON MIME examples:
160
208
  # application/json
@@ -173,15 +221,10 @@ module WebScrapingAI
173
221
  # @param [String] return_type some examples: "User", "Array<User>", "Hash<String, Integer>"
174
222
  def deserialize(response, return_type)
175
223
  body = response.body
176
-
177
- # handle file downloading - return the File instance processed in request callbacks
178
- # note that response body is empty when the file is written in chunks in request on_body callback
179
- return @tempfile if return_type == 'File'
180
-
181
224
  return nil if body.nil? || body.empty?
182
225
 
183
226
  # return response body directly for String return type
184
- return body if return_type == 'String'
227
+ return body.to_s if return_type == 'String'
185
228
 
186
229
  # ensuring a default content type
187
230
  content_type = response.headers['Content-Type'] || 'application/json'
@@ -191,7 +234,7 @@ module WebScrapingAI
191
234
  begin
192
235
  data = JSON.parse("[#{body}]", :symbolize_names => true)[0]
193
236
  rescue JSON::ParserError => e
194
- if %w(String Date DateTime).include?(return_type)
237
+ if %w(String Date Time).include?(return_type)
195
238
  data = body
196
239
  else
197
240
  raise e
@@ -216,9 +259,9 @@ module WebScrapingAI
216
259
  data.to_f
217
260
  when 'Boolean'
218
261
  data == true
219
- when 'DateTime'
262
+ when 'Time'
220
263
  # parse date time (expecting ISO 8601 format)
221
- DateTime.parse data
264
+ Time.parse data
222
265
  when 'Date'
223
266
  # parse date time (expecting ISO 8601 format)
224
267
  Date.parse data
@@ -236,46 +279,9 @@ module WebScrapingAI
236
279
  data.each { |k, v| hash[k] = convert_to_type(v, sub_type) }
237
280
  end
238
281
  else
239
- # models, e.g. Pet
240
- WebScrapingAI.const_get(return_type).build_from_hash(data)
241
- end
242
- end
243
-
244
- # Save response body into a file in (the defined) temporary folder, using the filename
245
- # from the "Content-Disposition" header if provided, otherwise a random filename.
246
- # The response body is written to the file in chunks in order to handle files which
247
- # size is larger than maximum Ruby String or even larger than the maximum memory a Ruby
248
- # process can use.
249
- #
250
- # @see Configuration#temp_folder_path
251
- def download_file(request)
252
- tempfile = nil
253
- encoding = nil
254
- request.on_headers do |response|
255
- content_disposition = response.headers['Content-Disposition']
256
- if content_disposition && content_disposition =~ /filename=/i
257
- filename = content_disposition[/filename=['"]?([^'"\s]+)['"]?/, 1]
258
- prefix = sanitize_filename(filename)
259
- else
260
- prefix = 'download-'
261
- end
262
- prefix = prefix + '-' unless prefix.end_with?('-')
263
- encoding = response.body.encoding
264
- tempfile = Tempfile.open(prefix, @config.temp_folder_path, encoding: encoding)
265
- @tempfile = tempfile
266
- end
267
- request.on_body do |chunk|
268
- chunk.force_encoding(encoding)
269
- tempfile.write(chunk)
270
- end
271
- request.on_complete do |response|
272
- if tempfile
273
- tempfile.close
274
- @config.logger.info "Temp file written to #{tempfile.path}, please copy the file to a proper folder "\
275
- "with e.g. `FileUtils.cp(tempfile.path, '/new/file/path')` otherwise the temp file "\
276
- "will be deleted automatically with GC. It's also recommended to delete the temp file "\
277
- "explicitly with `tempfile.delete`"
278
- end
282
+ # models (e.g. Pet) or oneOf
283
+ klass = WebScrapingAI.const_get(return_type)
284
+ klass.respond_to?(:openapi_one_of) ? klass.build(data) : klass.build_from_hash(data)
279
285
  end
280
286
  end
281
287
 
@@ -288,13 +294,13 @@ module WebScrapingAI
288
294
  filename.gsub(/.*[\/\\]/, '')
289
295
  end
290
296
 
291
- def build_request_url(path)
297
+ def build_request_url(path, opts = {})
292
298
  # Add leading and trailing slashes to path
293
299
  path = "/#{path}".gsub(/\/+/, '/')
294
- @config.base_url + path
300
+ @config.base_url(opts[:operation]) + path
295
301
  end
296
302
 
297
- # Update hearder and query params based on authentication settings.
303
+ # Update header and query params based on authentication settings.
298
304
  #
299
305
  # @param [Hash] header_params Header parameters
300
306
  # @param [Hash] query_params Query parameters
@@ -306,7 +312,7 @@ module WebScrapingAI
306
312
  case auth_setting[:in]
307
313
  when 'header' then header_params[auth_setting[:key]] = auth_setting[:value]
308
314
  when 'query' then query_params[auth_setting[:key]] = auth_setting[:value]
309
- else fail ArgumentError, 'Authentication token must be in `query` of `header`'
315
+ else fail ArgumentError, 'Authentication token must be in `query` or `header`'
310
316
  end
311
317
  end
312
318
  end
@@ -333,8 +339,8 @@ module WebScrapingAI
333
339
  # @param [Array] content_types array for Content-Type
334
340
  # @return [String] the Content-Type header (e.g. application/json)
335
341
  def select_header_content_type(content_types)
336
- # use application/json by default
337
- return 'application/json' if content_types.nil? || content_types.empty?
342
+ # return nil by default
343
+ return if content_types.nil? || content_types.empty?
338
344
  # use JSON when present, otherwise use the first one
339
345
  json_content_type = content_types.find { |s| json_mime?(s) }
340
346
  json_content_type || content_types.first
@@ -1,12 +1,12 @@
1
1
  =begin
2
2
  #WebScraping.AI
3
3
 
4
- #A client for https://webscraping.ai API. It provides a web scaping automation API with Chrome JS rendering, rotating proxies and builtin HTML parsing.
4
+ #WebScraping.AI scraping API provides GPT-powered tools with Chromium JavaScript rendering, rotating proxies, and built-in HTML parsing.
5
5
 
6
- The version of the OpenAPI document: 2.0.2
6
+ The version of the OpenAPI document: 3.1.2
7
7
  Contact: support@webscraping.ai
8
8
  Generated by: https://openapi-generator.tech
9
- OpenAPI Generator version: 4.3.1
9
+ OpenAPI Generator version: 7.2.0
10
10
 
11
11
  =end
12
12
 
@@ -32,6 +32,7 @@ module WebScrapingAI
32
32
  end
33
33
  else
34
34
  super arg
35
+ @message = arg
35
36
  end
36
37
  end
37
38
 
@@ -1,12 +1,12 @@
1
1
  =begin
2
2
  #WebScraping.AI
3
3
 
4
- #A client for https://webscraping.ai API. It provides a web scaping automation API with Chrome JS rendering, rotating proxies and builtin HTML parsing.
4
+ #WebScraping.AI scraping API provides GPT-powered tools with Chromium JavaScript rendering, rotating proxies, and built-in HTML parsing.
5
5
 
6
- The version of the OpenAPI document: 2.0.2
6
+ The version of the OpenAPI document: 3.1.2
7
7
  Contact: support@webscraping.ai
8
8
  Generated by: https://openapi-generator.tech
9
- OpenAPI Generator version: 4.3.1
9
+ OpenAPI Generator version: 7.2.0
10
10
 
11
11
  =end
12
12
 
@@ -21,6 +21,18 @@ module WebScrapingAI
21
21
  # Defines url base path
22
22
  attr_accessor :base_path
23
23
 
24
+ # Define server configuration index
25
+ attr_accessor :server_index
26
+
27
+ # Define server operation configuration index
28
+ attr_accessor :server_operation_index
29
+
30
+ # Default server variables
31
+ attr_accessor :server_variables
32
+
33
+ # Default server operation variables
34
+ attr_accessor :server_operation_variables
35
+
24
36
  # Defines API keys used with API Key authentications.
25
37
  #
26
38
  # @return [Hash] key: parameter name, value: parameter value (API key)
@@ -50,6 +62,16 @@ module WebScrapingAI
50
62
  # Defines the access token (Bearer) used with OAuth2.
51
63
  attr_accessor :access_token
52
64
 
65
+ # Defines a Proc used to fetch or refresh access tokens (Bearer) used with OAuth2.
66
+ # Overrides the access_token if set
67
+ # @return [Proc]
68
+ attr_accessor :access_token_getter
69
+
70
+ # Set this to return data as binary instead of downloading a temp file. When enabled (set to true)
71
+ # HTTP responses with return type `File` will be returned as a stream of binary data.
72
+ # Default to false.
73
+ attr_accessor :return_binary_data
74
+
53
75
  # Set this to enable/disable debugging. When enabled (set to true), HTTP request/response
54
76
  # details will be logged with `logger.debug` (see the `logger` attribute).
55
77
  # Default to false.
@@ -121,6 +143,7 @@ module WebScrapingAI
121
143
  # https://github.com/typhoeus/ethon/blob/master/lib/ethon/easy/queryable.rb#L96
122
144
  attr_accessor :params_encoding
123
145
 
146
+
124
147
  attr_accessor :inject_format
125
148
 
126
149
  attr_accessor :force_ending_format
@@ -129,15 +152,19 @@ module WebScrapingAI
129
152
  @scheme = 'https'
130
153
  @host = 'api.webscraping.ai'
131
154
  @base_path = ''
155
+ @server_index = nil
156
+ @server_operation_index = {}
157
+ @server_variables = {}
158
+ @server_operation_variables = {}
132
159
  @api_key = {}
133
160
  @api_key_prefix = {}
134
- @timeout = 0
135
161
  @client_side_validation = true
136
162
  @verify_ssl = true
137
163
  @verify_ssl_host = true
138
- @params_encoding = nil
139
164
  @cert_file = nil
140
165
  @key_file = nil
166
+ @timeout = 0
167
+ @params_encoding = nil
141
168
  @debugging = false
142
169
  @inject_format = false
143
170
  @force_ending_format = false
@@ -171,20 +198,34 @@ module WebScrapingAI
171
198
  @base_path = '' if @base_path == '/'
172
199
  end
173
200
 
174
- def base_url
175
- "#{scheme}://#{[host, base_path].join('/').gsub(/\/+/, '/')}".sub(/\/+\z/, '')
201
+ # Returns base URL for specified operation based on server settings
202
+ def base_url(operation = nil)
203
+ if operation_server_settings.key?(operation) then
204
+ index = server_operation_index.fetch(operation, server_index)
205
+ server_url(index.nil? ? 0 : index, server_operation_variables.fetch(operation, server_variables), operation_server_settings[operation])
206
+ else
207
+ server_index.nil? ? "#{scheme}://#{[host, base_path].join('/').gsub(/\/+/, '/')}".sub(/\/+\z/, '') : server_url(server_index, server_variables, nil)
208
+ end
176
209
  end
177
210
 
178
211
  # Gets API key (with prefix if set).
179
212
  # @param [String] param_name the parameter name of API key auth
180
- def api_key_with_prefix(param_name)
213
+ def api_key_with_prefix(param_name, param_alias = nil)
214
+ key = @api_key[param_name]
215
+ key = @api_key.fetch(param_alias, key) unless param_alias.nil?
181
216
  if @api_key_prefix[param_name]
182
- "#{@api_key_prefix[param_name]} #{@api_key[param_name]}"
217
+ "#{@api_key_prefix[param_name]} #{key}"
183
218
  else
184
- @api_key[param_name]
219
+ key
185
220
  end
186
221
  end
187
222
 
223
+ # Gets access_token using access_token_getter or uses the static access_token
224
+ def access_token_with_refresh
225
+ return access_token if access_token_getter.nil?
226
+ access_token_getter.call
227
+ end
228
+
188
229
  # Gets Basic Auth token string
189
230
  def basic_auth_token
190
231
  'Basic ' + ["#{username}:#{password}"].pack('m').delete("\r\n")
@@ -213,25 +254,32 @@ module WebScrapingAI
213
254
  ]
214
255
  end
215
256
 
257
+ def operation_server_settings
258
+ {
259
+ }
260
+ end
261
+
216
262
  # Returns URL based on server settings
217
263
  #
218
264
  # @param index array index of the server settings
219
265
  # @param variables hash of variable and the corresponding value
220
- def server_url(index, variables = {})
221
- servers = server_settings
266
+ def server_url(index, variables = {}, servers = nil)
267
+ servers = server_settings if servers == nil
222
268
 
223
269
  # check array index out of bound
224
- if (index < 0 || index >= servers.size)
225
- fail ArgumentError, "Invalid index #{index} when selecting the server. Must be less than #{servers.size}"
270
+ if (index.nil? || index < 0 || index >= servers.size)
271
+ fail ArgumentError, "Invalid index #{index} when selecting the server. Must not be nil and must be less than #{servers.size}"
226
272
  end
227
273
 
228
274
  server = servers[index]
229
275
  url = server[:url]
230
276
 
277
+ return url unless server.key? :variables
278
+
231
279
  # go through variable and assign a value
232
280
  server[:variables].each do |name, variable|
233
281
  if variables.key?(name)
234
- if (server[:variables][name][:enum_values].include? variables[name])
282
+ if (!server[:variables][name].key?(:enum_values) || server[:variables][name][:enum_values].include?(variables[name]))
235
283
  url.gsub! "{" + name.to_s + "}", variables[name]
236
284
  else
237
285
  fail ArgumentError, "The variable `#{name}` in the server URL has invalid value #{variables[name]}. Must be #{server[:variables][name][:enum_values]}."
@@ -244,5 +292,7 @@ module WebScrapingAI
244
292
 
245
293
  url
246
294
  end
295
+
296
+
247
297
  end
248
298
  end
@@ -1,38 +1,49 @@
1
1
  =begin
2
2
  #WebScraping.AI
3
3
 
4
- #A client for https://webscraping.ai API. It provides a web scaping automation API with Chrome JS rendering, rotating proxies and builtin HTML parsing.
4
+ #WebScraping.AI scraping API provides GPT-powered tools with Chromium JavaScript rendering, rotating proxies, and built-in HTML parsing.
5
5
 
6
- The version of the OpenAPI document: 2.0.2
6
+ The version of the OpenAPI document: 3.1.2
7
7
  Contact: support@webscraping.ai
8
8
  Generated by: https://openapi-generator.tech
9
- OpenAPI Generator version: 4.3.1
9
+ OpenAPI Generator version: 7.2.0
10
10
 
11
11
  =end
12
12
 
13
13
  require 'date'
14
+ require 'time'
14
15
 
15
16
  module WebScrapingAI
16
- class PageError
17
- # Response HTTP status code (403, 500, etc)
18
- attr_accessor :status_code
17
+ class Account
18
+ # Remaining API credits quota
19
+ attr_accessor :remaining_api_calls
19
20
 
20
- # Response HTTP status message
21
- attr_accessor :status_message
21
+ # Next billing cycle start time (UNIX timestamp)
22
+ attr_accessor :resets_at
23
+
24
+ # Remaining concurrent requests
25
+ attr_accessor :remaining_concurrency
22
26
 
23
27
  # Attribute mapping from ruby-style variable name to JSON key.
24
28
  def self.attribute_map
25
29
  {
26
- :'status_code' => :'status_code',
27
- :'status_message' => :'status_message'
30
+ :'remaining_api_calls' => :'remaining_api_calls',
31
+ :'resets_at' => :'resets_at',
32
+ :'remaining_concurrency' => :'remaining_concurrency'
28
33
  }
29
34
  end
30
35
 
36
+ # Returns all the JSON keys this model knows about
37
+ def self.acceptable_attributes
38
+ attribute_map.values
39
+ end
40
+
31
41
  # Attribute type mapping.
32
42
  def self.openapi_types
33
43
  {
34
- :'status_code' => :'Integer',
35
- :'status_message' => :'String'
44
+ :'remaining_api_calls' => :'Integer',
45
+ :'resets_at' => :'Integer',
46
+ :'remaining_concurrency' => :'Integer'
36
47
  }
37
48
  end
38
49
 
@@ -46,29 +57,34 @@ module WebScrapingAI
46
57
  # @param [Hash] attributes Model attributes in the form of hash
47
58
  def initialize(attributes = {})
48
59
  if (!attributes.is_a?(Hash))
49
- fail ArgumentError, "The input argument (attributes) must be a hash in `WebScrapingAI::PageError` initialize method"
60
+ fail ArgumentError, "The input argument (attributes) must be a hash in `WebScrapingAI::Account` initialize method"
50
61
  end
51
62
 
52
63
  # check to see if the attribute exists and convert string to symbol for hash key
53
64
  attributes = attributes.each_with_object({}) { |(k, v), h|
54
65
  if (!self.class.attribute_map.key?(k.to_sym))
55
- fail ArgumentError, "`#{k}` is not a valid attribute in `WebScrapingAI::PageError`. Please check the name to make sure it's valid. List of attributes: " + self.class.attribute_map.keys.inspect
66
+ fail ArgumentError, "`#{k}` is not a valid attribute in `WebScrapingAI::Account`. Please check the name to make sure it's valid. List of attributes: " + self.class.attribute_map.keys.inspect
56
67
  end
57
68
  h[k.to_sym] = v
58
69
  }
59
70
 
60
- if attributes.key?(:'status_code')
61
- self.status_code = attributes[:'status_code']
71
+ if attributes.key?(:'remaining_api_calls')
72
+ self.remaining_api_calls = attributes[:'remaining_api_calls']
73
+ end
74
+
75
+ if attributes.key?(:'resets_at')
76
+ self.resets_at = attributes[:'resets_at']
62
77
  end
63
78
 
64
- if attributes.key?(:'status_message')
65
- self.status_message = attributes[:'status_message']
79
+ if attributes.key?(:'remaining_concurrency')
80
+ self.remaining_concurrency = attributes[:'remaining_concurrency']
66
81
  end
67
82
  end
68
83
 
69
84
  # Show invalid properties with the reasons. Usually used together with valid?
70
85
  # @return Array for valid properties with the reasons
71
86
  def list_invalid_properties
87
+ warn '[DEPRECATED] the `list_invalid_properties` method is obsolete'
72
88
  invalid_properties = Array.new
73
89
  invalid_properties
74
90
  end
@@ -76,6 +92,7 @@ module WebScrapingAI
76
92
  # Check to see if the all the properties in the model are valid
77
93
  # @return true if the model is valid
78
94
  def valid?
95
+ warn '[DEPRECATED] the `valid?` method is obsolete'
79
96
  true
80
97
  end
81
98
 
@@ -84,8 +101,9 @@ module WebScrapingAI
84
101
  def ==(o)
85
102
  return true if self.equal?(o)
86
103
  self.class == o.class &&
87
- status_code == o.status_code &&
88
- status_message == o.status_message
104
+ remaining_api_calls == o.remaining_api_calls &&
105
+ resets_at == o.resets_at &&
106
+ remaining_concurrency == o.remaining_concurrency
89
107
  end
90
108
 
91
109
  # @see the `==` method
@@ -97,44 +115,40 @@ module WebScrapingAI
97
115
  # Calculates hash code according to all attributes.
98
116
  # @return [Integer] Hash code
99
117
  def hash
100
- [status_code, status_message].hash
118
+ [remaining_api_calls, resets_at, remaining_concurrency].hash
101
119
  end
102
120
 
103
121
  # Builds the object from hash
104
122
  # @param [Hash] attributes Model attributes in the form of hash
105
123
  # @return [Object] Returns the model itself
106
124
  def self.build_from_hash(attributes)
107
- new.build_from_hash(attributes)
108
- end
109
-
110
- # Builds the object from hash
111
- # @param [Hash] attributes Model attributes in the form of hash
112
- # @return [Object] Returns the model itself
113
- def build_from_hash(attributes)
114
125
  return nil unless attributes.is_a?(Hash)
115
- self.class.openapi_types.each_pair do |key, type|
116
- if type =~ /\AArray<(.*)>/i
126
+ attributes = attributes.transform_keys(&:to_sym)
127
+ transformed_hash = {}
128
+ openapi_types.each_pair do |key, type|
129
+ if attributes.key?(attribute_map[key]) && attributes[attribute_map[key]].nil?
130
+ transformed_hash["#{key}"] = nil
131
+ elsif type =~ /\AArray<(.*)>/i
117
132
  # check to ensure the input is an array given that the attribute
118
133
  # is documented as an array but the input is not
119
- if attributes[self.class.attribute_map[key]].is_a?(Array)
120
- self.send("#{key}=", attributes[self.class.attribute_map[key]].map { |v| _deserialize($1, v) })
134
+ if attributes[attribute_map[key]].is_a?(Array)
135
+ transformed_hash["#{key}"] = attributes[attribute_map[key]].map { |v| _deserialize($1, v) }
121
136
  end
122
- elsif !attributes[self.class.attribute_map[key]].nil?
123
- self.send("#{key}=", _deserialize(type, attributes[self.class.attribute_map[key]]))
124
- end # or else data not found in attributes(hash), not an issue as the data can be optional
137
+ elsif !attributes[attribute_map[key]].nil?
138
+ transformed_hash["#{key}"] = _deserialize(type, attributes[attribute_map[key]])
139
+ end
125
140
  end
126
-
127
- self
141
+ new(transformed_hash)
128
142
  end
129
143
 
130
144
  # Deserializes the data based on type
131
145
  # @param string type Data type
132
146
  # @param string value Value to be deserialized
133
147
  # @return [Object] Deserialized data
134
- def _deserialize(type, value)
148
+ def self._deserialize(type, value)
135
149
  case type.to_sym
136
- when :DateTime
137
- DateTime.parse(value)
150
+ when :Time
151
+ Time.parse(value)
138
152
  when :Date
139
153
  Date.parse(value)
140
154
  when :String
@@ -164,7 +178,9 @@ module WebScrapingAI
164
178
  end
165
179
  end
166
180
  else # model
167
- WebScrapingAI.const_get(type).build_from_hash(value)
181
+ # models (e.g. Pet) or oneOf
182
+ klass = WebScrapingAI.const_get(type)
183
+ klass.respond_to?(:openapi_any_of) || klass.respond_to?(:openapi_one_of) ? klass.build(value) : klass.build_from_hash(value)
168
184
  end
169
185
  end
170
186
 
@@ -190,7 +206,7 @@ module WebScrapingAI
190
206
  is_nullable = self.class.openapi_nullable.include?(attr)
191
207
  next if !is_nullable || (is_nullable && !instance_variable_defined?(:"@#{attr}"))
192
208
  end
193
-
209
+
194
210
  hash[param] = _to_hash(value)
195
211
  end
196
212
  hash
@@ -213,5 +229,7 @@ module WebScrapingAI
213
229
  value
214
230
  end
215
231
  end
232
+
216
233
  end
234
+
217
235
  end