paypal-rest-api 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 161078b6b9ff7513fe6634bc4e37c181374858dec0cac4261d5cc662d115787c
4
- data.tar.gz: 60346804bbd8a930f695a922a6ce07adaefca26e25f7777e70de0d9f5d87a01a
3
+ metadata.gz: 4e1ec764b9c93fe1fb6fe6f49e2fca6d5e0280a1182b0c4c4f54bee84c43b98d
4
+ data.tar.gz: c03728c11831a20270e38f111165747634298a3ca4d8bf97a26de9da9baa53b1
5
5
  SHA512:
6
- metadata.gz: e340f1e223aa903aed6fde693f4a16dc9cdf0ef3d474a633e171b7890eb016d8c42ef593117385419bd07c366bb257bbc0adbbcab8b193cb150523cd3dcaee46
7
- data.tar.gz: 74f017ec1aabca6d9a55599bacc32ee7d7d2c425ec109ec076d2f8072819d95047a07d763ed7b5ba0bd4b96a3b91a3aa3b2404d1a0602c2704028661b544a18b
6
+ metadata.gz: 26ca09bb472c049aa9a5cfa81485e11180dc5d1d19776e960beebb6f9db485b9d58ddda18f232943affb1b3d4c27e55ec3c82b4a55be92f16be6ea5c2f836b7e
7
+ data.tar.gz: f082f9263cffbc5a7a0561557284685eed6c2c2c67204d8c89271e82dedc007b63e3e616e49fc5a86925986df7c52b6afd5e053061785b2909d703c0017db4e7
data/README.md CHANGED
@@ -8,7 +8,7 @@ bundle add paypal-rest-api
8
8
 
9
9
  ## Features
10
10
 
11
- - Supported Ruby 2.6 - current Head
11
+ - Supported Ruby Versions - *(2.6 .. 3.3), head, jruby-9.4, truffleruby-24*
12
12
  - No dependencies;
13
13
  - Automatic authorization & reauthorization;
14
14
  - Auto-retries (configured);
@@ -35,7 +35,11 @@ PaypalAPI.client = PaypalAPI::Client.new(
35
35
  )
36
36
 
37
37
  # in your business logic
38
- response = PaypalAPI::Orders.show(order_id)
38
+ PaypalAPI.live? # => false
39
+ PaypalAPI.api_url # => "https://api-m.sandbox.paypal.com"
40
+ PaypalAPI.web_url # => "https://sandbox.paypal.com"
41
+
42
+ response = between redeploys::Orders.show(order_id)
39
43
  response = PaypalAPI::Orders.create(body: body)
40
44
  ```
41
45
 
@@ -49,6 +53,10 @@ client = PaypalAPI::Client.new(
49
53
  live: false
50
54
  )
51
55
 
56
+ client.live? # => false
57
+ client.api_url # => "https://api-m.sandbox.paypal.com"
58
+ client.web_url # => "https://sandbox.paypal.com"
59
+
52
60
  response = client.orders.show(order_id)
53
61
  response = client.orders.create(body: body)
54
62
  ```
@@ -91,7 +99,7 @@ response.request # Request that generates this response
91
99
 
92
100
  ## Configuration options
93
101
 
94
- PaypalAPI client accepts this additional options: `:live`, `:retries`, `:http_opts`
102
+ PaypalAPI client accepts this additional options: `:live`, `:retries`, `:http_opts`, `:cache`
95
103
 
96
104
  ### Option `:live`
97
105
 
@@ -108,8 +116,8 @@ client = PaypalAPI::Client.new(
108
116
  ### Option `:retries`
109
117
 
110
118
  This is a Hash with retries configuration.
111
- By default retries are enabled, 3 retries with 0.25, 0.75, 1.5 seconds delay.
112
- Default config: `{enabled: true, count: 3, sleep: [0.25, 0.75, 1.5]}`.
119
+ By default retries are enabled, 4 retries with 0, 0.25, 0.75, 1.5 seconds delay.
120
+ Default config: `{enabled: true, count: 4, sleep: [0, 0.25, 0.75, 1.5]}`.
113
121
  New options are merged with defaults.
114
122
  Please keep `sleep` array same size as `count`.
115
123
 
@@ -139,17 +147,33 @@ client = PaypalAPI::Client.new(
139
147
  )
140
148
  ```
141
149
 
150
+ ### Option `:cache`
151
+
152
+ This option can be added to save certificates to between redeploys to validate
153
+ webhooks offline. By default this gem has only in-memory caching.
154
+ Cache object must response to standard caching `#fetch(key, &block)` method.
155
+
156
+ By default it is `nil`, so downloaded certificates will be downloaded again after
157
+ redeploys.
158
+
159
+ ```ruby
160
+ client = PaypalAPI::Client.new(
161
+ cache: Rails.cache
162
+ # ...
163
+ )
164
+ ```
165
+
142
166
  ## Webhoooks verification
143
167
 
144
168
  Webhooks can be verified [offline](https://developer.paypal.com/api/rest/webhooks/rest/#link-selfverificationmethod)
145
169
  or [online](https://developer.paypal.com/api/rest/webhooks/rest/#link-postbackmethod).
146
170
  Method `PaypalAPI.verify_webhook(webhook_id:, headers:, raw_body:)`
147
- verifies webhook. It to verify webhook OFFLINE and it fallbacks
148
- to ONLINE if offline verification returns false to be sure you don't miss a
171
+ verifies webhook. It verifies webhook OFFLINE and fallbacks
172
+ to ONLINE if initial verification returns false to be sure you don't miss a
149
173
  valid webhook.
150
174
 
151
- When some required header is missing it will raise
152
- `PaypalAPI::WebhooksVerifier::MissingHeader` error.
175
+ When some required header is missing the
176
+ `PaypalAPI::WebhooksVerifier::MissingHeader` error will be raised.
153
177
 
154
178
  Example of Rails controller with webhook verification:
155
179
 
@@ -192,9 +216,17 @@ Callbacks are registered on `client` object.
192
216
  Each callback receive `request` and `context` variables.
193
217
  `context` can be modified manually to save state between callbacks.
194
218
 
195
- `:after_success` and `:after_fail` callbacks have additional `response` argument
219
+ Arguments:
220
+
221
+ - `:before` - (request, context)
222
+ - `:after_success` - (request, context, response)
223
+ - `:after_fail` - (request, context, response)
224
+ - `:after_network_error` - (request, context, error)
225
+
226
+ `Context` argument contains `retries_enabled` and `retries_count` and
227
+ `retry_number` keys by default.
196
228
 
197
- `:after_network_error` callback has additional `error` argument
229
+ Examples:
198
230
 
199
231
  ```ruby
200
232
  PaypalAPI.client.add_callback(:before) do |request, context|
@@ -202,7 +234,7 @@ PaypalAPI.client.add_callback(:before) do |request, context|
202
234
  context[:starts_at] = Process.clock_gettime(Process::CLOCK_MONOTONIC)
203
235
  end
204
236
 
205
- PaypalAPI.client.add_callback(:after) do |request, context, response|
237
+ PaypalAPI.client.add_callback(:after_success) do |request, context, response|
206
238
  ends_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
207
239
  duration = ends_at - context[:starts_at]
208
240
 
@@ -229,7 +261,7 @@ end
229
261
 
230
262
  PaypalAPI.client.add_callback(:after_network_error) do |request, context, error|
231
263
  SomeLogger.error(
232
- 'PaypalAPI network connection error'
264
+ 'PaypalAPI network connection error',
233
265
  method: request.method,
234
266
  uri: request.uri.to_s,
235
267
  error: error.message,
@@ -316,15 +348,15 @@ All API endpoints accept this parameters:
316
348
 
317
349
  ### Payments
318
350
 
319
- - `PaypalAPI::AuthorizedPayment.show`
320
- - `PaypalAPI::AuthorizedPayment.capture`
321
- - `PaypalAPI::AuthorizedPayment.reauthorize`
322
- - `PaypalAPI::AuthorizedPayment.void`
351
+ - `PaypalAPI::AuthorizedPayments.show`
352
+ - `PaypalAPI::AuthorizedPayments.capture`
353
+ - `PaypalAPI::AuthorizedPayments.reauthorize`
354
+ - `PaypalAPI::AuthorizedPayments.void`
323
355
 
324
356
  <!-- -->
325
357
 
326
- - `PaypalAPI::CapturedPayment.show`
327
- - `PaypalAPI::CapturedPayment.refund`
358
+ - `PaypalAPI::CapturedPayments.show`
359
+ - `PaypalAPI::CapturedPayments.refund`
328
360
 
329
361
  <!-- -->
330
362
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.0
1
+ 0.2.0
@@ -43,7 +43,7 @@ module PaypalAPI
43
43
 
44
44
  default_headers = {
45
45
  "content-type" => "application/x-www-form-urlencoded",
46
- "authorization" => "Basic #{["#{client.config.client_id}:#{client.config.client_secret}"].pack("m0")}"
46
+ "authorization" => "Basic #{["#{client.env.client_id}:#{client.env.client_secret}"].pack("m0")}"
47
47
  }
48
48
 
49
49
  client.post(PATH, query: query, body: body, headers: merge_headers!(default_headers, headers))
@@ -5,7 +5,18 @@ module PaypalAPI
5
5
  # PaypalAPI Client
6
6
  #
7
7
  class Client
8
- attr_reader :config, :callbacks
8
+ # Paypal environment
9
+ attr_reader :env
10
+
11
+ # Gem Configuration
12
+ #
13
+ # @return [Config] Gem Configuration
14
+ attr_reader :config
15
+
16
+ # Registered callbacks
17
+ #
18
+ # @return [Hash] Registered callbacks
19
+ attr_reader :callbacks
9
20
 
10
21
  # Initializes Client
11
22
  # @api public
@@ -18,15 +29,9 @@ module PaypalAPI
18
29
  #
19
30
  # @return [Client] Initialized client
20
31
  #
21
- def initialize(client_id:, client_secret:, live: nil, http_opts: nil, retries: nil, cache: nil)
22
- @config = PaypalAPI::Config.new(
23
- client_id: client_id,
24
- client_secret: client_secret,
25
- live: live,
26
- http_opts: http_opts,
27
- retries: retries,
28
- cache: cache
29
- )
32
+ def initialize(client_id:, client_secret:, live: false, http_opts: nil, retries: nil, cache: nil)
33
+ @env = PaypalAPI::Environment.new(client_id: client_id, client_secret: client_secret, live: live)
34
+ @config = PaypalAPI::Config.new(http_opts: http_opts, retries: retries, cache: cache)
30
35
 
31
36
  @callbacks = {
32
37
  before: [],
@@ -38,10 +43,34 @@ module PaypalAPI
38
43
  @access_token = nil
39
44
  end
40
45
 
46
+ # Checks if PayPal LIVE environment enabled
47
+ # @return [Boolean] Checks if PayPal LIVE environment enabled
48
+ def live?
49
+ env.live?
50
+ end
51
+
52
+ # Checks if PayPal SANDBOX environment enabled
53
+ # @return [Boolean] Checks if PayPal SANDBOX environment enabled
54
+ def sandbox?
55
+ env.sandbox?
56
+ end
57
+
58
+ # Base API URL
59
+ # @return [String] Base API URL
60
+ def api_url
61
+ env.api_url
62
+ end
63
+
64
+ # Base WEB URL
65
+ # @return [String] Base WEB URL
66
+ def web_url
67
+ env.web_url
68
+ end
69
+
41
70
  # Registers callback
42
71
  #
43
72
  # @param callback_name [Symbol] Callback name.
44
- # Allowed values: :before, :after_success, :after_faile, :after_network_error
73
+ # Allowed values: :before, :after_success, :after_fail, :after_network_error
45
74
  #
46
75
  # @param block [Proc] Block that must be call
47
76
  # For `:before` callback proc should accept 2 params -
@@ -89,6 +118,7 @@ module PaypalAPI
89
118
 
90
119
  #
91
120
  # Verifies Webhook
121
+ #
92
122
  # It requires one-time request to download and cache certificate.
93
123
  # If local verification returns false it tries to verify webhook online.
94
124
  #
@@ -98,7 +128,7 @@ module PaypalAPI
98
128
  # class Webhooks::PaypalController < ApplicationController
99
129
  # def create
100
130
  # webhook_id = ENV['PAYPAL_WEBHOOK_ID'] # PayPal registered webhook ID for current URL
101
- # headers = request.headers # must be a Hash
131
+ # headers = request.headers # must respond to #[] to get headers
102
132
  # body = request.raw_post # must be a raw String body
103
133
  #
104
134
  # webhook_is_valid = PaypalAPI.verify_webhook(webhook_id: webhook_id, headers: headers, body: body)
@@ -2,71 +2,32 @@
2
2
 
3
3
  module PaypalAPI
4
4
  #
5
- # Stores configuration for PaypalAPI Client
5
+ # Stores client requests configuration
6
6
  #
7
7
  class Config
8
- # Live PayPal URL
9
- LIVE_URL = "https://api-m.paypal.com"
10
-
11
- # Sandbox PayPal URL
12
- SANDBOX_URL = "https://api-m.sandbox.paypal.com"
13
-
14
8
  # Default config options
15
9
  DEFAULTS = {
16
- live: false,
17
10
  http_opts: {}.freeze,
18
- retries: {enabled: true, count: 3, sleep: [0.25, 0.75, 1.5].freeze}.freeze
11
+ retries: {enabled: true, count: 4, sleep: [0, 0.25, 0.75, 1.5].freeze}.freeze
19
12
  }.freeze
20
13
 
21
- attr_reader :client_id, :client_secret, :live, :http_opts, :retries, :certs_cache
14
+ attr_reader :http_opts, :retries, :certs_cache
22
15
 
23
16
  # Initializes Config
24
17
  #
25
- # @param client_id [String] PayPal client id
26
- # @param client_secret [String] PayPal client secret
27
- # @param live [Boolean] PayPal live/sandbox mode
28
18
  # @param http_opts [Hash] Net::Http opts for all requests
29
19
  # @param retries [Hash] Retries configuration
30
20
  # @param cache [#read, nil] Application cache to store certificates to validate webhook events locally.
31
- # Must respond to #read(key) and #write(key, expires_in: Integer)
21
+ # Must respond to #fetch(key, &block)
32
22
  #
33
23
  # @return [Client] Initialized config object
34
24
  #
35
- def initialize(client_id:, client_secret:, live: nil, http_opts: nil, retries: nil, cache: nil)
36
- @client_id = client_id
37
- @client_secret = client_secret
38
- @live = with_default(:live, live)
39
- @http_opts = with_default(:http_opts, http_opts)
40
- @retries = with_default(:retries, retries)
25
+ def initialize(http_opts: nil, retries: {}, cache: nil)
26
+ @http_opts = http_opts || DEFAULTS[:http_opts]
27
+ @retries = DEFAULTS[:retries].merge(retries || {})
41
28
  @certs_cache = WebhookVerifier::CertsCache.new(cache)
42
29
 
43
30
  freeze
44
31
  end
45
-
46
- # @return [String] PayPal live or sandbox URL
47
- def url
48
- live ? LIVE_URL : SANDBOX_URL
49
- end
50
-
51
- #
52
- # Instance representation string. Default was overwritten to hide secrets
53
- #
54
- def inspect
55
- "#<#{self.class.name} live: #{live}>"
56
- end
57
-
58
- alias_method :to_s, :inspect
59
-
60
- private
61
-
62
- def with_default(option_name, value)
63
- default = DEFAULTS.fetch(option_name)
64
-
65
- case value
66
- when NilClass then default
67
- when Hash then default.merge(value)
68
- else value
69
- end
70
- end
71
32
  end
72
33
  end
@@ -0,0 +1,75 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PaypalAPI
4
+ # Sandbox API PayPal URL
5
+ SANDBOX_API_URL = "https://api-m.sandbox.paypal.com"
6
+
7
+ # Live API PayPal URL
8
+ LIVE_API_URL = "https://api-m.paypal.com"
9
+
10
+ # Sandbox PayPal Web URL
11
+ SANDBOX_WEB_URL = "https://sandbox.paypal.com"
12
+
13
+ # Live PayPal Web URL
14
+ LIVE_WEB_URL = "https://paypal.com"
15
+
16
+ #
17
+ # PayPal environment info
18
+ #
19
+ class Environment
20
+ # PayPal client_id
21
+ attr_accessor :client_id
22
+
23
+ # PayPal client_secret
24
+ attr_reader :client_secret
25
+
26
+ # PayPal API base URL
27
+ attr_reader :api_url
28
+
29
+ # PayPal web URL
30
+ attr_reader :web_url
31
+
32
+ # Initializes Environment
33
+ #
34
+ # @param client_id [String] PayPal client id
35
+ # @param client_secret [String] PayPal client secret
36
+ # @param live [Boolean] PayPal live/sandbox mode
37
+ #
38
+ # @return [Client] Initialized config object
39
+ #
40
+ def initialize(client_id:, client_secret:, live: false)
41
+ @live = live || false
42
+ @api_url = live ? LIVE_API_URL : SANDBOX_API_URL
43
+ @web_url = live ? LIVE_WEB_URL : SANDBOX_WEB_URL
44
+ @client_id = client_id
45
+ @client_secret = client_secret
46
+ freeze
47
+ end
48
+
49
+ #
50
+ # Instance representation string. Default was overwritten to hide secrets
51
+ # @return [String]
52
+ #
53
+ def inspect
54
+ "#<#{self.class.name} live: #{@live}>"
55
+ end
56
+
57
+ alias_method :to_s, :inspect
58
+
59
+ #
60
+ # Checks if live environment enabled
61
+ # @return [Boolean]
62
+ #
63
+ def live?
64
+ @live
65
+ end
66
+
67
+ #
68
+ # Checks if sandbox environment enabled
69
+ # @return [Boolean]
70
+ #
71
+ def sandbox?
72
+ !live?
73
+ end
74
+ end
75
+ end
@@ -107,7 +107,7 @@ module PaypalAPI
107
107
  end
108
108
 
109
109
  def build_http_uri(path, query)
110
- uri = URI.join(client.config.url, path)
110
+ uri = URI.join(client.env.api_url, path)
111
111
  uri.query = URI.encode_www_form(query) if query && !query.empty?
112
112
  uri
113
113
  end
@@ -5,7 +5,7 @@ module PaypalAPI
5
5
  # Executes PaypalAPI::Request and returns PaypalAPI::Response or raises PaypalAPI::Error
6
6
  #
7
7
  class RequestExecutor
8
- attr_reader :client, :request, :http_opts, :context, :retries, :callbacks, :callbacks_context
8
+ attr_reader :client, :request, :http_opts, :retries, :callbacks, :callbacks_context
9
9
 
10
10
  def initialize(client, request)
11
11
  @client = client
@@ -13,7 +13,7 @@ module PaypalAPI
13
13
  @http_opts = {use_ssl: request.uri.is_a?(URI::HTTPS), **client.config.http_opts}
14
14
  @retries = client.config.retries
15
15
  @callbacks = client.callbacks
16
- @callbacks_context = {retries_count: retries[:count]}
16
+ @callbacks_context = {retries_enabled: retries[:enabled], retries_count: retries[:count]}
17
17
  end
18
18
 
19
19
  #
@@ -35,8 +35,10 @@ module PaypalAPI
35
35
 
36
36
  run_callbacks(:before)
37
37
  response = execute_net_http_request
38
- rescue *NetworkErrorBuilder::ERRORS => error
39
- will_retry = !retries_limit_reached?(retry_number)
38
+ rescue => error
39
+ raise error if NetworkErrorBuilder::ERRORS.none? { |network_error_class| error.is_a?(network_error_class) }
40
+
41
+ will_retry = retries[:enabled] && !retries_limit_reached?(retry_number)
40
42
  callbacks_context[:will_retry] = will_retry
41
43
  run_callbacks(:after_network_error, error)
42
44
  raise NetworkErrorBuilder.call(request: request, error: error) unless will_retry
@@ -48,7 +50,7 @@ module PaypalAPI
48
50
  run_callbacks(:after_success, response)
49
51
  response
50
52
  else
51
- will_retry = retryable?(response, retry_number)
53
+ will_retry = retries[:enabled] && retryable?(response, retry_number)
52
54
  callbacks_context[:will_retry] = will_retry
53
55
  run_callbacks(:after_fail, response)
54
56
  will_retry ? retry_request(retry_number) : response
@@ -104,7 +106,7 @@ module PaypalAPI
104
106
  end
105
107
 
106
108
  def run_callbacks(callback_name, resp = nil)
107
- callbacks[callback_name].each { |callback| callback.call(request, context, resp) }
109
+ callbacks[callback_name].each { |callback| callback.call(request, callbacks_context, resp) }
108
110
  end
109
111
  end
110
112
  end
data/lib/paypal-api.rb CHANGED
@@ -210,6 +210,7 @@ end
210
210
 
211
211
  require_relative "paypal-api/access_token"
212
212
  require_relative "paypal-api/api_collection"
213
+ require_relative "paypal-api/environment"
213
214
  require_relative "paypal-api/client"
214
215
  require_relative "paypal-api/config"
215
216
  require_relative "paypal-api/error"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paypal-rest-api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrey Glushkov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-08-30 00:00:00.000000000 Z
11
+ date: 2024-09-02 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: PayPal REST API with no dependencies.
14
14
  email:
@@ -45,6 +45,7 @@ files:
45
45
  - lib/paypal-api/api_collections/webhooks.rb
46
46
  - lib/paypal-api/client.rb
47
47
  - lib/paypal-api/config.rb
48
+ - lib/paypal-api/environment.rb
48
49
  - lib/paypal-api/error.rb
49
50
  - lib/paypal-api/failed_request_error_builder.rb
50
51
  - lib/paypal-api/network_error_builder.rb