forked from stripe/stripe-ruby
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add API resource instance methods to StripeClient
This change introduces a proof-of-concept to add convenience methods to access API resources through a StripeClient for per-client configuration. This first iteration only allows for the `api_key` to be configured but can be extended to allow other options such as `stripe_version`, which should solve stripe#872. The primary workhorse for this feature is a new module called `Stripe::ClientAPIOperations` that defines instance methods on `StripeClient` when it is included. A `ClientProxy` is used to send any method calls to an API resource with the instantiated client injected. There are a few noteworthy aspects of this approach: - Many resources are namespaced, which introduces a unique challenge when it comes to method chaining calls (e.g. client.issuing.authorizations). In order to handle those cases, we create a `ClientProxy` object for the root namespace (e.g., "issuing") and define all resource methods (e.g. "authorizations") at once to avoid re-defining the proxy object when there are multiple resources per namespace. - Sigma deviates from other namespaced API resources and does not have an `OBJECT_NAME` separated by a period. We account for that nuance directly. - `method_missing` is substantially slower than direct calls. Therefore, methods are defined where possible but `method_missing` is still used at the last step when delegating resource methods to the actual resource.
- Loading branch information
1 parent
403f9b2
commit fcd6ae4
Showing
7 changed files
with
172 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# frozen_string_literal: true | ||
|
||
module Stripe | ||
# Define instance methods on the including class (i.e. StripeClient) | ||
# to access API resources. | ||
module ClientAPIOperations | ||
# Proxy object to inject the client into API resources | ||
class ClientProxy | ||
def initialize(client:, resource: nil) | ||
@client = client | ||
@resource = resource | ||
end | ||
|
||
attr_reader :client | ||
|
||
def with_client(client) | ||
@client = client | ||
self | ||
end | ||
|
||
def method_missing(method, *args) | ||
super unless @resource | ||
@resource.send(method, *args << { client: @client }) || super | ||
end | ||
|
||
def respond_to_missing?(symbol, include_private = false) | ||
super unless @resource | ||
@resource.respond_to?(symbol) || super | ||
end | ||
end | ||
|
||
def self.included(base) | ||
base.class_eval do | ||
# Sigma, unlike other nested API objects, is not separated by a period | ||
# so we modify the object name to follow the expected convention. | ||
api_resources = Stripe::Util.api_object_classes.transform_keys do |key| | ||
key == "scheduled_query_run" ? "sigma.scheduled_query_run" : key | ||
end | ||
|
||
# Group namespaces that have mutiple resourses | ||
grouped_resources = api_resources.group_by do |key, _| | ||
key.include?(".") ? key.split(".").first : key | ||
end | ||
|
||
grouped_resources.each do |resource_namespace, resources| | ||
# Namespace resource names are separated with a period by convention. | ||
if resources[0][0].include?(".") | ||
|
||
# Defines the methods required for chaining calls for resources that | ||
# are namespaced. A proxy object is created so that all resource | ||
# methods can be defined at once. | ||
proxy = ClientProxy.new(client: nil) | ||
resources.each do |resource_name, resource_class| | ||
method_name = resource_name.split(".").last | ||
proxy.define_singleton_method("#{method_name}s") do | ||
ClientProxy.new(client: proxy.client, resource: resource_class) | ||
end | ||
end | ||
|
||
# Defines the first method for resources that are namespaced. By | ||
# convention these methods are singular. A proxy object is returned | ||
# so that the client can be injected along the method chain. | ||
define_method(resource_namespace) do | ||
proxy.with_client(self) | ||
end | ||
else | ||
# Defines plural methods for non-namespaced resources | ||
define_method("#{resource_namespace}s".to_sym) do | ||
ClientProxy.new(client: self, resource: resources[0][1]) | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters