Joel Taylor 299e9ea0ab Raise an error when requests params are invalid (#874)
There are two kinds of API operations: collection and element specific.
The signature between the two is slightly different:
  - **collection**: (params, opts)
  - **element specific**: (id, params, opts)

If a user doesn't realize the difference, they may attempt to use the
collection signature when performing an element specific operation like:
```
Stripe::PaymentIntent.cancel('pi_1234', 'sk_test_key')
 # Results in an error: NoMethodError: undefined method `key?' for "sk_test"
```

The resulting error message isn't very useful for debugging.

Instead,this PR adds a message letting the user know what it's expecting:
`request params should be either a Hash or nil (was a String)`
2019-10-31 09:53:19 -07:00

81 lines
2.2 KiB
Ruby

# frozen_string_literal: true
module Stripe
module APIOperations
module Request
module ClassMethods
def request(method, url, params = {}, opts = {})
params ||= {}
error_on_invalid_params(params)
warn_on_opts_in_params(params)
opts = Util.normalize_opts(opts)
error_on_non_string_user_opts(opts)
opts[:client] ||= StripeClient.active_client
headers = opts.clone
api_key = headers.delete(:api_key)
api_base = headers.delete(:api_base)
client = headers.delete(:client)
# Assume all remaining opts must be headers
resp, opts[:api_key] = client.execute_request(
method, url,
api_base: api_base, api_key: api_key,
headers: headers, params: params
)
# Hash#select returns an array before 1.9
opts_to_persist = {}
opts.each do |k, v|
opts_to_persist[k] = v if Util::OPTS_PERSISTABLE.include?(k)
end
[resp, opts_to_persist]
end
private def error_on_non_string_user_opts(opts)
Util::OPTS_USER_SPECIFIED.each do |opt|
next unless opts.key?(opt)
val = opts[opt]
next if val.nil?
next if val.is_a?(String)
raise ArgumentError,
"request option '#{opt}' should be a string value " \
"(was a #{val.class})"
end
end
private def error_on_invalid_params(params)
return if params.nil? || params.is_a?(Hash)
raise ArgumentError,
"request params should be either a Hash or nil " \
"(was a #{params.class})"
end
private def warn_on_opts_in_params(params)
Util::OPTS_USER_SPECIFIED.each do |opt|
if params.key?(opt)
warn("WARNING: '#{opt}' should be in opts instead of params.")
end
end
end
end
def self.included(base)
base.extend(ClassMethods)
end
protected def request(method, url, params = {}, opts = {})
opts = @opts.merge(Util.normalize_opts(opts))
self.class.request(method, url, params, opts)
end
end
end
end