Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for APIs in the new API version 2024-09-30.acacia #1458

Merged
merged 7 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@ Layout/FirstHashElementIndentation:
Layout/LineLength:
Exclude:
- "lib/stripe/object_types.rb"
- "lib/stripe/stripe_client.rb"
- "lib/stripe/resources/**/*.rb"
- "lib/stripe/services/**/*.rb"
- "test/**/*.rb"

Metrics/AbcSize:
Enabled: false

Metrics/BlockLength:
Max: 40
Exclude:
Expand All @@ -29,18 +34,37 @@ Metrics/BlockLength:
Metrics/ClassLength:
Enabled: false

# There are several methods with many branches in api_requestor due to
# request logic.
Metrics/CyclomaticComplexity:
Exclude:
- "lib/stripe/api_requestor.rb"
- "lib/stripe/util.rb"

Metrics/PerceivedComplexity:
Exclude:
- "lib/stripe/api_requestor.rb"
- "lib/stripe/util.rb"

Metrics/MethodLength:
# There's ~2 long methods in `StripeClient` and one in `NestedResource`. If
# There's ~2 long methods in `APIRequestor` and one in `NestedResource`. If
# we want to truncate those a little, we could move this to be closer to ~30
# (but the default of 10 is probably too short).
Max: 55
Exclude:
- "lib/stripe/services/v1_services.rb"

Metrics/ModuleLength:
Enabled: false

Metrics/ParameterLists:
# There's 2 methods in `StripeClient` that have long parameter lists.
Max: 8
# Optional parameters should be consistent across libraries, we need not be
# concerned about this. Was introduced with adding `base_address`
Exclude:
- "lib/stripe/api_operations/request.rb"
- "lib/stripe/stripe_object.rb"

Style/AccessModifierDeclarations:
EnforcedStyle: inline
Expand Down
8 changes: 4 additions & 4 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# Offense count: 2
Lint/HashCompareByIdentity:
Exclude:
- 'lib/stripe/stripe_client.rb'
- 'lib/stripe/api_requestor.rb'

# Offense count: 26
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
Expand Down Expand Up @@ -47,7 +47,7 @@ Style/CaseLikeIf:
# This cop supports unsafe autocorrection (--autocorrect-all).
Style/CombinableLoops:
Exclude:
- 'lib/stripe/stripe_client.rb'
- 'lib/stripe/api_requestor.rb'

# Offense count: 39
# Configuration parameters: AllowedConstants.
Expand All @@ -59,7 +59,7 @@ Style/Documentation:
# Configuration parameters: AllowSplatArgument.
Style/HashConversion:
Exclude:
- 'lib/stripe/stripe_client.rb'
- 'lib/stripe/api_requestor.rb'

# Offense count: 3
# This cop supports unsafe autocorrection (--autocorrect-all).
Expand All @@ -81,7 +81,7 @@ Style/StringConcatenation:
- 'lib/stripe/oauth.rb'
- 'lib/stripe/resources/bank_account.rb'
- 'lib/stripe/resources/source.rb'
- 'lib/stripe/stripe_client.rb'
- 'lib/stripe/api_requestor.rb'
- 'test/stripe/api_resource_test.rb'
- 'test/stripe/stripe_client_test.rb'
- 'test/stripe/webhook_test.rb'
2 changes: 1 addition & 1 deletion OPENAPI_VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v1255
v1268
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -346,13 +346,14 @@ If you:
- 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`.
you can now use the `raw_request` method on `StripeClient`.

```ruby
resp = Stripe.raw_request(:post, "/v1/beta_endpoint", {param: 123}, {stripe_version: "2022-11-15; feature_beta=v3"})
client = Stripe::StripeClient.new(...)
resp = client.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)
deserialized_resp = client.deserialize(resp.http_body)
```

## Support
Expand Down
11 changes: 11 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
## Running an example

From the examples folder, run:
`RUBYLIB=../lib ruby your_example.rb`

## Adding a new example

1. Clone new_example.rb
2. Implement your example
3. Run it (as per above)
4. 👍
47 changes: 47 additions & 0 deletions examples/meter_event_stream.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# frozen_string_literal: true

require "stripe"
require "date"

class MeterEventManager
attr_accessor :api_key, :meter_event_session

def initialize(api_key)
@api_key = api_key
@meter_event_session = nil
end

def refresh_meter_event_session
return unless @meter_event_session.nil? || DateTime.parse(@meter_event_session.expires_at) <= DateTime.now

# Create a new meter event session in case the existing session expired
client = Stripe::StripeClient.new(api_key)
@meter_event_session = client.v2.billing.meter_event_session.create
end

def send_meter_event(meter_event)
# Refresh the meter event session if necessary
refresh_meter_event_session

# Create a meter event with the current session's authentication token
client = Stripe::StripeClient.new(meter_event_session.authentication_token)
client.v2.billing.meter_event_stream.create(
events: [meter_event]
)
end
end

# Send meter events
api_key = "{{API_KEY}}"
customer_id = "{{CUSTOMER_ID}}"

manager = MeterEventManager.new(api_key)
manager.send_meter_event(
{
event_name: "alpaca_ai_tokens",
payload: {
"stripe_customer_id" => customer_id,
"value" => "25",
},
}
)
24 changes: 24 additions & 0 deletions examples/new_example.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

require "stripe"
require "date"

class NewExample
attr_accessor :api_key

def initialize(api_key)
@api_key = api_key
end

def do_something_great
puts "Hello World"
# client = Stripe::StripeClient.new(api_key)
# client.v1
end
end

# Send meter events
api_key = "{{API_KEY}}"

example = NewExample.new(api_key)
example.do_something_great
28 changes: 28 additions & 0 deletions examples/stripe_webhook_handler.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# frozen_string_literal: true
# typed: false

require "stripe"
require "sinatra"

api_key = ENV.fetch("STRIPE_API_KEY", nil)
# Retrieve the webhook secret from the environment variable
webhook_secret = ENV.fetch("WEBHOOK_SECRET", nil)

client = Stripe::StripeClient.new(api_key)

post "/webhook" do
webhook_body = request.body.read
sig_header = request.env["HTTP_STRIPE_SIGNATURE"]
thin_event = client.parse_thin_event(webhook_body, sig_header, webhook_secret)

# Fetch the event data to understand the failure
event = client.v2.core.events.retrieve(thin_event.id)
if event.instance_of? Stripe::V1BillingMeterErrorReportTriggeredEvent
meter = event.fetch_related_object
meter_id = meter.id
puts "Success!", meter_id
end

# Record the failures and alert your team
status 200
end
40 changes: 15 additions & 25 deletions lib/stripe.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,34 @@
# API resource support classes
require "stripe/errors"
require "stripe/object_types"
require "stripe/event_types"
require "stripe/request_options"
require "stripe/util"
require "stripe/connection_manager"
require "stripe/multipart_encoder"
require "stripe/api_requestor"
require "stripe/stripe_service"
require "stripe/stripe_client"
require "stripe/stripe_object"
require "stripe/stripe_response"
require "stripe/list_object"
require "stripe/v2_list_object"
require "stripe/search_result_object"
require "stripe/error_object"
require "stripe/api_resource"
require "stripe/api_resource_test_helpers"
require "stripe/singleton_api_resource"
require "stripe/webhook"
require "stripe/stripe_configuration"
require "stripe/thin_event"

# Named API resources
require "stripe/resources"
require "stripe/services"

# OAuth
require "stripe/oauth"
require "stripe/services/oauth_service"

module Stripe
DEFAULT_CA_BUNDLE_PATH = __dir__ + "/data/ca-certificates.crt"
Expand All @@ -60,6 +68,12 @@ module Stripe
LEVEL_ERROR = Logger::ERROR
LEVEL_INFO = Logger::INFO

# API base constants
DEFAULT_API_BASE = "https://api.stripe.com"
DEFAULT_CONNECT_BASE = "https://connect.stripe.com"
DEFAULT_UPLOAD_BASE = "https://files.stripe.com"
DEFAULT_METER_EVENTS_BASE = "https://meter-events.stripe.com"

@app_info = nil

@config = Stripe::StripeConfiguration.setup
Expand All @@ -76,6 +90,7 @@ class << self
def_delegators :@config, :api_base, :api_base=
def_delegators :@config, :uploads_base, :uploads_base=
def_delegators :@config, :connect_base, :connect_base=
def_delegators :@config, :meter_events_base, :meter_events_base=
def_delegators :@config, :open_timeout, :open_timeout=
def_delegators :@config, :read_timeout, :read_timeout=
def_delegators :@config, :write_timeout, :write_timeout=
Expand Down Expand Up @@ -117,31 +132,6 @@ 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 = {}, usage = [])
resp, = execute_resource_request(method, url, params, opts, usage)

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, ["raw_request"])
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?
22 changes: 1 addition & 21 deletions lib/stripe/api_operations/nested_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ def nested_resource_class_methods(resource, path: nil, operations: nil,
end
end

# rubocop:disable Metrics/MethodLength
private def define_operation(
resource,
operation,
Expand All @@ -54,26 +53,8 @@ def nested_resource_class_methods(resource, path: nil, operations: nil,
)
end
when :retrieve
# TODO: (Major) Split params_or_opts to params and opts and get rid of the complicated way to add params
define_singleton_method(:"retrieve_#{resource}") \
do |id, nested_id, params_or_opts = {}, definitely_opts = nil|
opts = nil
params = nil
if definitely_opts.nil?
unrecognized_key = params_or_opts.keys.find { |k| !Util::OPTS_USER_SPECIFIED.include?(k) }
if unrecognized_key
raise ArgumentError,
"Unrecognized request option: #{unrecognized_key}. Did you mean to specify this as " \
"retrieve params? " \
"If so, you must explicitly pass an opts hash as a fourth argument. " \
"For example: .retrieve(#{id}, #{nested_id}, {#{unrecognized_key}: 'foo'}, {})"
end

opts = params_or_opts
else
opts = definitely_opts
params = params_or_opts
end
do |id, nested_id, params = {}, opts = {}|
request_stripe_object(
method: :get,
path: send(resource_url_method, id, nested_id),
Expand Down Expand Up @@ -115,7 +96,6 @@ def nested_resource_class_methods(resource, path: nil, operations: nil,
raise ArgumentError, "Unknown operation: #{operation.inspect}"
end
end
# rubocop:enable Metrics/MethodLength
end
end
end
Loading
Loading