diff --git a/.rubocop.yml b/.rubocop.yml index 57d9cd9dd..b3b299b21 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -38,6 +38,10 @@ Metrics/MethodLength: Metrics/ModuleLength: Enabled: false +Metrics/ParameterLists: + # There's 2 methods in `StripeClient` that have long parameter lists. + Max: 8 + Style/AccessModifierDeclarations: EnforcedStyle: inline diff --git a/README.md b/README.md index 6c17dcc05..8be82deaf 100644 --- a/README.md +++ b/README.md @@ -338,6 +338,23 @@ If your beta feature requires a `Stripe-Version` header to be sent, set the `Str Stripe.add_beta_version("feature_beta", "v3") ``` +### Custom requests + +If you: + +- would like to send a request to an undocumented API (for example you are in a private beta) +- prefer to bypass the method definitions in the library and specify your request details directly, +- used the method `Stripe::APIResource.request(...)` to specify your own requests, which will soon be broken + +you can now use the `raw_request` method on `Stripe`. + +```ruby +resp = Stripe.raw_request(:post, "/v1/beta_endpoint", {param: 123}, {stripe_version: "2022-11-15; feature_beta=v3"}) + +# (Optional) resp is a StripeResponse. You can use `Stripe.deserialize` to get a StripeObject. +deserialized_resp = Stripe.deserialize(resp.http_body) +``` + ## Support New features and bug fixes are released on the latest major version of the Stripe Ruby library. If you are on an older major version, we recommend that you upgrade to the latest in order to use the new features and bug fixes including those for security vulnerabilities. Older major versions of the package will continue to be available for use, but will not be receiving any updates. diff --git a/lib/stripe.rb b/lib/stripe.rb index 13e060bf7..51548b80c 100644 --- a/lib/stripe.rb +++ b/lib/stripe.rb @@ -117,6 +117,31 @@ def self.set_app_info(name, partner_id: nil, url: nil, version: nil) version: version, } end + + class RawRequest + include Stripe::APIOperations::Request + + def initialize + @opts = {} + end + + def execute(method, url, params = {}, opts = {}) + resp, = execute_resource_request(method, url, params, opts) + + resp + end + end + + # Sends a request to Stripe REST API + def self.raw_request(method, url, params = {}, opts = {}) + req = RawRequest.new + req.execute(method, url, params, opts) + end + + def self.deserialize(data) + data = JSON.parse(data) if data.is_a?(String) + Util.convert_to_stripe_object(data, {}) + end end Stripe.log_level = ENV["STRIPE_LOG"] unless ENV["STRIPE_LOG"].nil? diff --git a/lib/stripe/stripe_client.rb b/lib/stripe/stripe_client.rb index 0041bbe58..57c9eb704 100644 --- a/lib/stripe/stripe_client.rb +++ b/lib/stripe/stripe_client.rb @@ -462,6 +462,7 @@ def self.maybe_gc_connection_managers headers = request_headers(api_key, method) .update(Util.normalize_headers(headers)) + url = api_url(path, api_base) # Merge given query parameters with any already encoded in the path. @@ -879,6 +880,7 @@ def self.maybe_gc_connection_managers end headers["Stripe-Version"] = config.api_version if config.api_version + headers["Stripe-Account"] = config.stripe_account if config.stripe_account user_agent = @system_profiler.user_agent diff --git a/test/stripe/raw_request_test.rb b/test/stripe/raw_request_test.rb new file mode 100644 index 000000000..4eebf9fbd --- /dev/null +++ b/test/stripe/raw_request_test.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require File.expand_path("../test_helper", __dir__) + +class RawRequestTest < Test::Unit::TestCase + context "raw_request" do + should "send get request and return a response" do + expected_body = "{\"id\": \"acc_123\"}" + req = nil + + stub_request(:get, "#{Stripe.api_base}/v1/accounts/acc_123") + .with { |request| req = request } + .to_return(body: expected_body) + + resp = Stripe.raw_request(:get, "/v1/accounts/acc_123") + + assert_equal expected_body, resp.http_body + assert_equal "application/x-www-form-urlencoded", req.headers["Content-Type"] + assert_equal Stripe::ApiVersion::CURRENT, req.headers["Stripe-Version"] + end + + should "send post request with body and return a response" do + expected_body = "{\"id\": \"acc_123\"}" + req = nil + + stub_request(:post, "#{Stripe.api_base}/v1/accounts/acc_123") + .with(body: "p1=1&p2=string") + .with { |request| req = request } + .to_return(body: expected_body) + + resp = Stripe.raw_request(:post, "/v1/accounts/acc_123", { p1: 1, p2: "string" }) + + assert_equal expected_body, resp.http_body + assert_equal "application/x-www-form-urlencoded", req.headers["Content-Type"] + assert_equal Stripe::ApiVersion::CURRENT, req.headers["Stripe-Version"] + end + end +end diff --git a/test/stripe_test.rb b/test/stripe_test.rb index 151fd29e0..fbc603700 100644 --- a/test/stripe_test.rb +++ b/test/stripe_test.rb @@ -134,4 +134,42 @@ class StripeTest < Test::Unit::TestCase assert_equal "client", Stripe.client_id end end + + context "deserialize" do + should "deserializes string into known object" do + expected_body = "{\"id\": \"acc_123\", \"object\": \"account\"}" + + obj = Stripe.deserialize(expected_body) + + assert_equal obj.class, Stripe::Account + assert_equal obj.id, "acc_123" + end + + should "deserializes string into unknown object" do + expected_body = "{\"id\": \"acc_123\", \"object\": \"unknown\"}" + + obj = Stripe.deserialize(expected_body) + + assert_equal obj.class, Stripe::StripeObject + assert_equal obj.id, "acc_123" + end + + should "deserializes hash into known object" do + expected_body = { "id" => "acc_123", "object" => "account" } + + obj = Stripe.deserialize(expected_body) + + assert_equal obj.class, Stripe::Account + assert_equal obj.id, "acc_123" + end + + should "deserializes hash into unknown object" do + expected_body = { "id" => "acc_123", "object" => "unknown" } + + obj = Stripe.deserialize(expected_body) + + assert_equal obj.class, Stripe::StripeObject + assert_equal obj.id, "acc_123" + end + end end