Class: RecurlyApi::Client
- Inherits:
-
Object
- Object
- RecurlyApi::Client
- Includes:
- Caching, ExceptionHandler, Logging, RateLimiting
- Defined in:
- lib/recurly_api/client.rb,
lib/recurly_api/client/plans.rb,
lib/recurly_api/client/accounts.rb,
lib/recurly_api/client/subscriptions.rb,
lib/recurly_api/client/other_requests.rb
Overview
This class fetches the data of Recurly API end-points
Constant Summary collapse
- API_DEFAULTS =
{ base_host: 'v3.recurly.com', api_version: 'v2021-02-25' }.freeze
- RECORDS_LIMIT =
request for The number of records to return per page
20
Constants included from Caching
RecurlyApi::Caching::CACHE_SETTINGS
Constants included from RateLimiting
RateLimiting::RATE_LIMIT_MAX_RETRIES
Instance Attribute Summary collapse
-
#additional_headers ⇒ Object
request attributes for request_api method.
-
#api_endpoint ⇒ Object
Initialize method attributes.
-
#api_version ⇒ Object
Initialize method attributes.
-
#authorization_key ⇒ Object
Initialize method attributes.
-
#base_host ⇒ Object
Initialize method attributes.
-
#cache_key_name ⇒ Object
request attributes for request_api method.
-
#cache_settings ⇒ Object
Initialize method attributes.
-
#final_response ⇒ Object
response attributes.
-
#http_method ⇒ Object
request attributes for request_api method.
-
#optional_params ⇒ Object
request attributes for request_api method.
-
#path_name ⇒ Object
request attributes for request_api method.
-
#payload ⇒ Object
request attributes for request_api method.
-
#payload_name ⇒ Object
request attributes for request_api method.
-
#query_params ⇒ Object
request attributes for request_api method.
-
#recurly_response ⇒ Object
response attributes.
-
#site_id ⇒ Object
Initialize method attributes.
Attributes included from Caching
#cache_expires_in, #cache_key, #ignore_caching
Attributes included from RateLimiting
Attributes included from Logging
Instance Method Summary collapse
-
#account_info(ssor_id:, **optional_params) ⇒ Object
Fetch Account Info– { developers.recurly.com/api/v2021-02-25/index.html#operation/get_account }.
-
#account_subscriptions(ssor_id:, recurly_query_params: {}, **optional_params) ⇒ Object
Fetch Account Subscriptions — { developers.recurly.com/api/v2021-02-25/index.html#operation/list_account_subscriptions } for other params refer documentation.
-
#cancel_subscription(sub_id_or_uuid) ⇒ Object
Cancel a subscription by its id or UUID.
-
#check_user_subscription(ssor_id:, plan_code: nil) ⇒ Object
Checking if user already has subscription OR Checking if user has a subscription for particular plan by its code ————— Usage ex: client.check_user_subscription(ssor_id: ‘4900-0272-6875’, plan_code: ‘000150d03d’) response => { :success=>true, :status_code=>200, :has_subscription=>true }.
-
#coupon_redemptions(ssor_id:, **optional_params) ⇒ Object
Show the coupon redemptions for an account – { developers.recurly.com/api/v2021-02-25/index.html#tag/coupon_redemption } For ID no prefix is used e.g.
-
#create_subscription(ssor_id:, billing_token:, plan_code:, gateway_code: nil, account_info: {}) ⇒ Object
Create subscription(new purchase) by ssor_id(Recurly Account code) { developers.recurly.com/api/v2021-02-25/index.html#operation/create_purchase } TODO: fetch user email, first_name, last_name by ssor_id connecting to SsorClient Better to pass first_name, last_name, email fetched from Checkout Page, instead of extra DB call to SSOR to get the user details.
-
#deactivate_account(ssor_id:) ⇒ Object
Deactivate account — { developers.recurly.com/api/v2021-02-25/index.html#operation/deactivate_account }.
- #ensure_request_headers ⇒ Object
- #fetch_response_from_recurly(cache_recurly_resp: false) ⇒ Object
- #handle_error_response(code, json_body) ⇒ Object
- #handle_recurly_error_response(resp) ⇒ Object
- #handle_recurly_response! ⇒ Object
-
#initialize(authorization_key:, site_id:, base_host: nil, api_version: nil, ratelimit_retries: RATE_LIMIT_MAX_RETRIES, cache_settings: CACHE_SETTINGS) ⇒ Client
constructor
Initialize a client.
-
#list_plans(recurly_query_params: {}, **optional_params) ⇒ Object
Examples: query_params = { limit: 2, order: :asc, ids: [‘abc’, ‘def’..etc], :sort: <value>} client.list_plans(recurly_query_params: query_params, bypass_cache: true) client.list_plans(recurly_query_params: query_params, cache_expires_in: 120, payload_name: :fetch_plans) client.list_plans(recurly_query_params: query_params).
-
#plan_add_ons(plan_id:, **optional_params) ⇒ Object
Fetch Plan Info– { developers.recurly.com/api/v2021-02-25/index.html#operation/list_plan_add_ons }.
-
#plan_info(plan_id:, **optional_params) ⇒ Object
Fetch Plan Info– { developers.recurly.com/api/v2021-02-25/index.html#operation/get_plan}.
-
#request_api(path_name:, http_method: :get, query_params: {}, payload: {}, additional_headers: {}, cache_key_name: nil, **optional_params) ⇒ Object
Ful Usage Example: Below is the example for ‘request_api’ call that includes all options res = request_api(path_name: ‘plans’, # required http_method: :get, # optional, :post|put|patch|delete query_params: recurly_query_params, # optional payload: {}, # optional, request body params additional_headers: { ‘User-Agent’: ‘abc’, ..}, # optional cache_key_name: ‘key123’, # optional, defaults to method_name bypass_caching: true, # optionals, default false payload_name: ‘list_all_plans’, # optional defaults to caller method_name cache_expiry_in: 300 # optional default 300 ) RestClient retry { blog.appsignal.com/2018/05/16/ensure-retry-and-reraise-exceptions-in-ruby.html } rubocop:disable Metrics/AbcSize rubocop:disable Metrics/PerceivedComplexity rubocop:disable Metrics/CyclomaticComplexity rubocop:disable Metrics/MethodLength.
-
#site_subscriptions(recurly_query_params: {}, **optional_params) ⇒ Object
List a site’s subscriptions { developers.recurly.com/api/v2021-02-25/#operation/list_account_subscriptions } ii.
Methods included from Caching
#cache, #cache_key_with_prefix, #cache_prefix_name, #caching_enabled?, #check_logs_for_caching_info, #fetch_response_from_cache, #ignore_caching?, #write_final_resp_to_cache
Methods included from RateLimiting
#rate_limit_exceed_response, #rate_limit_exceeded?, #retry_on_rate_limit_exceed
Methods included from ExceptionHandler
#recurly_api_exception_handler
Methods included from Logging
#logger_cache_heading, #logger_heading
Constructor Details
#initialize(authorization_key:, site_id:, base_host: nil, api_version: nil, ratelimit_retries: RATE_LIMIT_MAX_RETRIES, cache_settings: CACHE_SETTINGS) ⇒ Client
Initialize a client. KeyWord args are optional while initializing and defaults to the values present in recurly_config.yml(Rails only), Ex: If you want to use custom ‘api_version’ instead predefined, initialize client as below,
rc = RecurlyApi::Client.new(api_version: 'v2019-10-10')
rubocop:disable Metrics/ParameterLists
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/recurly_api/client.rb', line 50 def initialize(authorization_key:, site_id:, base_host: nil, api_version: nil, ratelimit_retries: RATE_LIMIT_MAX_RETRIES, cache_settings: CACHE_SETTINGS) @authorization_key = @site_id = site_id raise ArgumentError, "'authorization_key' must be set to a non-nil value" if @authorization_key.nil? raise ArgumentError, "'site_id' must be set to a non-nil value" if @site_id.nil? @base_host = base_host || API_DEFAULTS[:base_host] @api_version = api_version || API_DEFAULTS[:api_version] @api_endpoint = "https://#{@base_host}/sites/#{@site_id}" @ratelimit_retries = ratelimit_retries @cache_settings = cache_settings @cache_expires_in = cache_settings[:default_expiry] @ignore_caching = cache_settings[:bypass] end |
Instance Attribute Details
#additional_headers ⇒ Object
request attributes for request_api method
32 33 34 |
# File 'lib/recurly_api/client.rb', line 32 def additional_headers @additional_headers end |
#api_endpoint ⇒ Object
Initialize method attributes
29 30 31 |
# File 'lib/recurly_api/client.rb', line 29 def api_endpoint @api_endpoint end |
#api_version ⇒ Object
Initialize method attributes
29 30 31 |
# File 'lib/recurly_api/client.rb', line 29 def api_version @api_version end |
#authorization_key ⇒ Object
Initialize method attributes
29 30 31 |
# File 'lib/recurly_api/client.rb', line 29 def @authorization_key end |
#base_host ⇒ Object
Initialize method attributes
29 30 31 |
# File 'lib/recurly_api/client.rb', line 29 def base_host @base_host end |
#cache_key_name ⇒ Object
request attributes for request_api method
32 33 34 |
# File 'lib/recurly_api/client.rb', line 32 def cache_key_name @cache_key_name end |
#cache_settings ⇒ Object
Initialize method attributes
29 30 31 |
# File 'lib/recurly_api/client.rb', line 29 def cache_settings @cache_settings end |
#final_response ⇒ Object
response attributes
36 37 38 |
# File 'lib/recurly_api/client.rb', line 36 def final_response @final_response end |
#http_method ⇒ Object
request attributes for request_api method
32 33 34 |
# File 'lib/recurly_api/client.rb', line 32 def http_method @http_method end |
#optional_params ⇒ Object
request attributes for request_api method
32 33 34 |
# File 'lib/recurly_api/client.rb', line 32 def optional_params @optional_params end |
#path_name ⇒ Object
request attributes for request_api method
32 33 34 |
# File 'lib/recurly_api/client.rb', line 32 def path_name @path_name end |
#payload ⇒ Object
request attributes for request_api method
32 33 34 |
# File 'lib/recurly_api/client.rb', line 32 def payload @payload end |
#payload_name ⇒ Object
request attributes for request_api method
32 33 34 |
# File 'lib/recurly_api/client.rb', line 32 def payload_name @payload_name end |
#query_params ⇒ Object
request attributes for request_api method
32 33 34 |
# File 'lib/recurly_api/client.rb', line 32 def query_params @query_params end |
#recurly_response ⇒ Object
response attributes
36 37 38 |
# File 'lib/recurly_api/client.rb', line 36 def recurly_response @recurly_response end |
#site_id ⇒ Object
Initialize method attributes
29 30 31 |
# File 'lib/recurly_api/client.rb', line 29 def site_id @site_id end |
Instance Method Details
#account_info(ssor_id:, **optional_params) ⇒ Object
Fetch Account Info– { developers.recurly.com/api/v2021-02-25/index.html#operation/get_account }
10 11 12 13 14 15 16 |
# File 'lib/recurly_api/client/accounts.rb', line 10 def account_info(ssor_id:, **optional_params) # cache_key should be uniq for each account(here ssor_id is uniq) # final cache key with prefix: tribune_recurly_api.account_info.<abcdef> cache_key_name = "account_info.#{ssor_id}" request_api(path_name: "accounts/code-#{ssor_id}", cache_key_name: cache_key_name, **optional_params) end |
#account_subscriptions(ssor_id:, recurly_query_params: {}, **optional_params) ⇒ Object
Fetch Account Subscriptions — { developers.recurly.com/api/v2021-02-25/index.html#operation/list_account_subscriptions }
for other params refer documentation
11 12 13 14 15 16 17 18 19 |
# File 'lib/recurly_api/client/subscriptions.rb', line 11 def account_subscriptions(ssor_id:, recurly_query_params: {}, **optional_params) path = "accounts/code-#{ssor_id}/subscriptions" self.cache_expires_in = optional_params[:cache_expires_in] || cache_settings[:subscription_expiry] unless bypass_caching? # cache_key should be uniq for each account(here ssor_id is uniq) # final cache key with prefix: tribune_recurly_api.account_subscriptions.<abcdef> cache_key_name = "account_subscriptions.#{ssor_id}" request_api(path_name: path, query_params: recurly_query_params, cache_key_name: cache_key_name, **optional_params) end |
#cancel_subscription(sub_id_or_uuid) ⇒ Object
Cancel a subscription by its id or UUID
96 97 98 99 |
# File 'lib/recurly_api/client/subscriptions.rb', line 96 def cancel_subscription(sub_id_or_uuid) path = "subscriptions/#{sub_id_or_uuid}/cancel" request_api(path_name: path, http_method: :put) end |
#check_user_subscription(ssor_id:, plan_code: nil) ⇒ Object
Checking if user already has subscription OR Checking if user has a subscription for particular plan by its code
Usage ex: client.check_user_subscription(ssor_id: ‘4900-0272-6875’, plan_code: ‘000150d03d’) response => { :success=>true, :status_code=>200, :has_subscription=>true }
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/recurly_api/client/subscriptions.rb', line 31 def check_user_subscription(ssor_id:, plan_code: nil) query_params = { limit: 2 } resp = account_subscriptions(ssor_id: ssor_id, recurly_query_params: query_params) if resp[:success] has_subscription = false subs = resp[:payload]['data'] has_subscription = true if subs&.any? if plan_code sub = subs.detect { |s| s['plan']['code'].eql?(plan_code) } has_subscription = sub ? true : false end { success: true, status: 200, has_subscription: has_subscription } else resp end end |
#coupon_redemptions(ssor_id:, **optional_params) ⇒ Object
Show the coupon redemptions for an account – { developers.recurly.com/api/v2021-02-25/index.html#tag/coupon_redemption } For ID no prefix is used e.g. e28zov4fw0v2
. For code use prefix code-
, e.g. code-bob
.
10 11 12 13 14 15 16 |
# File 'lib/recurly_api/client/other_requests.rb', line 10 def coupon_redemptions(ssor_id:, **optional_params) # cache_key should be uniq for each account(here ssor_id is uniq) # final cache key with prefix: tribune_recurly_api.coupon_redemptions.<abcdef> cache_key_name = "coupon_redemptions.#{ssor_id}" request_api(path_name: "accounts/code-#{ssor_id}/coupon_redemptions", cache_key_name: cache_key_name, **optional_params) end |
#create_subscription(ssor_id:, billing_token:, plan_code:, gateway_code: nil, account_info: {}) ⇒ Object
Create subscription(new purchase) by ssor_id(Recurly Account code) { developers.recurly.com/api/v2021-02-25/index.html#operation/create_purchase } TODO: fetch user email, first_name, last_name by ssor_id connecting to SsorClient Better to pass first_name, last_name, email fetched from Checkout Page,
instead of extra DB call to SSOR to get the user details
79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/recurly_api/client/subscriptions.rb', line 79 def create_subscription(ssor_id:, billing_token:, plan_code:, gateway_code: nil, account_info: {}) account = { code: ssor_id, billing_info: { token_id: billing_token } } purchase_payload = { currency: 'USD', account: account.merge!(account_info), subscriptions: [{ plan_code: plan_code }] } purchase_payload[:gateway_code] = gateway_code if gateway_code path = 'purchases' request_api(path_name: path, http_method: :post, payload: purchase_payload) end |
#deactivate_account(ssor_id:) ⇒ Object
Deactivate account — { developers.recurly.com/api/v2021-02-25/index.html#operation/deactivate_account }
22 23 24 25 |
# File 'lib/recurly_api/client/accounts.rb', line 22 def deactivate_account(ssor_id:) path = "accounts/code-#{ssor_id}" request_api(path_name: path, http_method: :delete) end |
#ensure_request_headers ⇒ Object
161 162 163 164 165 166 |
# File 'lib/recurly_api/client.rb', line 161 def ensure_request_headers accept_header = "application/vnd.recurly.#{api_version}+json" { "Authorization": , "Content-Type": 'application/json', accept: accept_header }.merge!(additional_headers) end |
#fetch_response_from_recurly(cache_recurly_resp: false) ⇒ Object
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/recurly_api/client.rb', line 141 def fetch_response_from_recurly(cache_recurly_resp: false) # rescue/raise all your all exceptions in ExceptionHandler's method recurly_api_exception_handler do end_point = "#{api_endpoint}/#{path_name}" headers = ensure_request_headers.merge!(params: query_params) self.recurly_response = RestClient::Request.execute(method: http_method, url: end_point, payload: payload.empty? ? nil : payload.to_json, headers: headers) self.final_response = handle_recurly_response! retry_on_rate_limit_exceed # don't cache rate_limit_exceed_response if cache_recurly_resp && !rate_limit_exceeded? write_final_resp_to_cache logger.info("#{logger_cache_heading}: Recurly Response saved to cache_store with Key: #{cache_key_with_prefix}") end final_response end end |
#handle_error_response(code, json_body) ⇒ Object
182 183 184 185 186 |
# File 'lib/recurly_api/client.rb', line 182 def handle_error_response(code, json_body) { success: false, status_code: code, error: json_body['error']['type'], message: json_body['error']['message'] } end |
#handle_recurly_error_response(resp) ⇒ Object
188 189 190 191 192 193 |
# File 'lib/recurly_api/client.rb', line 188 def handle_recurly_error_response(resp) json_body = JSON.parse(resp.body) return unless json_body['error'] handle_error_response(resp.code, json_body) end |
#handle_recurly_response! ⇒ Object
168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/recurly_api/client.rb', line 168 def handle_recurly_response! if rate_limit_exceeded? rate_limit_exceed_response else json_body = JSON.parse(recurly_response.body) if json_body['error'] handle_error_response(recurly_response.code, json_body) else { success: true, status_code: recurly_response.code, "#{payload_name}": json_body } end end end |
#list_plans(recurly_query_params: {}, **optional_params) ⇒ Object
Examples:
query_params = { limit: 2, order: :asc, ids: ['abc', 'def'..etc], :sort: <value>}
client.list_plans(recurly_query_params: query_params, bypass_cache: true)
client.list_plans(recurly_query_params: query_params, cache_expires_in: 120, payload_name: :fetch_plans)
client.list_plans(recurly_query_params: query_params)
27 28 29 30 31 32 33 |
# File 'lib/recurly_api/client/plans.rb', line 27 def list_plans(recurly_query_params: {}, **optional_params) # payload_name = optional_params[:payload_name] # if not present default value is :payload # cache_key_name = 'list_all_plans' # optional by default cache_key is caller method_name in receiver i.e. list_plans here self.cache_expires_in = optional_params[:cache_expires_in] || cache_settings[:plan_expiry] unless bypass_caching? # cache_key_name = 'all_plans' # for custom cache key pass as extra argument request_api(path_name: 'plans', query_params: recurly_query_params, **optional_params) end |
#plan_add_ons(plan_id:, **optional_params) ⇒ Object
Fetch Plan Info– { developers.recurly.com/api/v2021-02-25/index.html#operation/list_plan_add_ons }
54 55 56 57 58 59 60 61 |
# File 'lib/recurly_api/client/plans.rb', line 54 def plan_add_ons(plan_id:, **optional_params) self.cache_expires_in = optional_params[:cache_expires_in] || cache_settings[:plan_expiry] unless bypass_caching? # cache_key should be uniq for each plan(here plan_id is uniq) # final cache key with prefix: tribune_recurly_api.plan_info.<abcdef> cache_key_name = "plan_info.#{plan_id}.add_ons" request_api(path_name: "plans/#{plan_id}/add_ons", cache_key_name: cache_key_name, **optional_params) end |
#plan_info(plan_id:, **optional_params) ⇒ Object
Fetch Plan Info– { developers.recurly.com/api/v2021-02-25/index.html#operation/get_plan}
40 41 42 43 44 45 46 47 |
# File 'lib/recurly_api/client/plans.rb', line 40 def plan_info(plan_id:, **optional_params) self.cache_expires_in = optional_params[:cache_expires_in] || cache_settings[:plan_expiry] unless bypass_caching? # cache_key should be uniq for each plan(here plan_id is uniq) # final cache key with prefix: tribune_recurly_api.plan_info.<abcdef> cache_key_name = "plan_info.#{plan_id}" request_api(path_name: "plans/#{plan_id}", cache_key_name: cache_key_name, **optional_params) end |
#request_api(path_name:, http_method: :get, query_params: {}, payload: {}, additional_headers: {}, cache_key_name: nil, **optional_params) ⇒ Object
Ful Usage Example: Below is the example for ‘request_api’ call that includes all options
res = request_api(path_name: 'plans', # required
http_method: :get, # optional, :post|put|patch|delete
query_params: recurly_query_params, # optional
payload: {}, # optional, request body params
additional_headers: { 'User-Agent': 'abc', ..}, # optional
cache_key_name: 'key123', # optional, defaults to method_name
bypass_caching: true, # optionals, default false
payload_name: 'list_all_plans', # optional defaults to caller method_name
cache_expiry_in: 300 # optional default 300
)
RestClient retry { blog.appsignal.com/2018/05/16/ensure-retry-and-reraise-exceptions-in-ruby.html } rubocop:disable Metrics/AbcSize rubocop:disable Metrics/PerceivedComplexity rubocop:disable Metrics/CyclomaticComplexity rubocop:disable Metrics/MethodLength
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/recurly_api/client.rb', line 103 def request_api(path_name:, http_method: :get, query_params: {}, payload: {}, additional_headers: {}, cache_key_name: nil, **optional_params) raise ArgumentError, "'request path' must be set to a non-nil value" if path_name.nil? self.path_name = path_name # set the HTTP Verb (caching is only done for HTTP GET requests) self.http_method = http_method # set the HTTP Verb (caching is only done for HTTP GET requests) self.query_params = query_params self.payload = payload self.additional_headers = additional_headers self.cache_key_name = cache_key_name self.optional_params = optional_params # optional params ===> self.payload_name = optional_params[:payload_name] || 'payload' self.ignore_caching = optional_params[:bypass_caching] || ignore_caching self.cache_expires_in = optional_params[:cache_expires_in] || cache_expires_in # caller_method_name = caller_locations.first.label # Ruby 2.0 + caller_method_name = caller(1..1).first[/`(.*)'/, 1] # Prior Ruby 2.0 self.cache_key = cache_key_name || caller_method_name # fallbacks to caller method if cache_key_name not present # TODO: remove below method once integration testing is completed, also remove unnecessary logs check_logs_for_caching_info # Cashing related stuff... (caching is performed on response only on :get requests when it is enabled) # by default Cache bypassed for non rails applications if caching_enabled? && !bypass_caching? && http_method.eql?(:get) cached_response = fetch_response_from_cache # Do NOT use a falsy check because we need to distinguish 'false' from 'nil' if cached_response.nil? fetch_response_from_recurly(cache_recurly_resp: true) else logger.info("#{logger_cache_heading}: response returned from cache store and key is: #{cache_key_with_prefix}") cached_response end else logger.warn("#{logger_cache_heading}: caching of Recurly Response completely bypassed") fetch_response_from_recurly end end |
#site_subscriptions(recurly_query_params: {}, **optional_params) ⇒ Object
List a site’s subscriptions { developers.recurly.com/api/v2021-02-25/#operation/list_account_subscriptions }
ii. :limit [Integer] Limit number of records 1-200.
iii. :order [String] Sort order.
iv: :sort [String] Sort field. You *really* only want to sort by <updated_at> in ascending
ex: recurly_query_params = { limit: RECORDS_LIMIT, order: :asc, .….} ex: client.site_subscriptions(params)
59 60 61 62 |
# File 'lib/recurly_api/client/subscriptions.rb', line 59 def site_subscriptions(recurly_query_params: {}, **optional_params) self.cache_expires_in = optional_params[:cache_expires_in] || cache_settings[:subscription_expiry] unless bypass_caching? request_api(path_name: 'subscriptions', query_params: recurly_query_params, **optional_params) end |