paypal-rest-api 0.0.1 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -5,92 +5,119 @@ module PaypalAPI
5
5
  # Common interface for all errors
6
6
  #
7
7
  class Error < StandardError
8
- attr_reader :response, :request, :error_name, :error_message, :error_debug_id, :error_details
8
+ # @return [Response, nil] Returned response with non-200 status code
9
+ attr_reader :response
10
+
11
+ # @return [Request] Sent request
12
+ attr_reader :request
13
+
14
+ # @return [String] Error name provided by PayPal or Net::HTTP network error name
15
+ attr_reader :error_name
16
+
17
+ # @return [String] Error message provided by PayPal or Net::HTTP network error message
18
+ attr_reader :error_message
19
+
20
+ # @return [String, nil] Error debug_id returned by PayPal
21
+ attr_reader :error_debug_id
22
+
23
+ # @see https://developer.paypal.com/api/rest/responses/#link-examples
24
+ # @return [Array, nil] Error details returned by PayPal
25
+ attr_reader :error_details
26
+
27
+ # @return [String, nil] PayPal-Request-Id header assigned to request
28
+ attr_reader :paypal_request_id
9
29
  end
10
30
 
11
31
  #
12
- # Raised when PayPal responds with any status code except 200, 201, 202, 204
32
+ # Namespace for specific PaypalAPI errors
13
33
  #
14
- class FailedRequest < Error
15
- def initialize(message = nil, request:, response:)
16
- super(message)
17
- @request = request
18
- @response = response
19
-
20
- body = response.body
21
- data = body.is_a?(Hash) ? body : {}
22
- @error_name = data[:name] || data[:error] || response.http_response.class.name
23
- @error_message = data[:message] || data[:error_description] || response.http_body.to_s
24
- @error_debug_id = data[:debug_id]
25
- @error_details = data[:details]
34
+ module Errors
35
+ #
36
+ # Raised when PayPal responds with any status code except 200, 201, 202, 204
37
+ #
38
+ class FailedRequest < Error
39
+ def initialize(message = nil, request:, response:)
40
+ super(message)
41
+ @request = request
42
+ @response = response
43
+
44
+ body = response.body
45
+ data = body.is_a?(Hash) ? body : {}
46
+ @error_name = data[:name] || data[:error] || response.http_response.class.name
47
+ @error_message = data[:message] || data[:error_description] || response.http_body.to_s
48
+ @error_debug_id = data[:debug_id]
49
+ @error_details = data[:details]
50
+ @paypal_request_id = request.http_request["paypal-request-id"]
51
+ end
26
52
  end
27
- end
28
53
 
29
- #
30
- # Raised when a network raised when executing the request
31
- # List of network errors can be found in errors/network_error_builder.rb
32
- #
33
- class NetworkError < Error
34
- def initialize(message = nil, request:, error:)
35
- super(message)
36
- @request = request
37
- @response = nil
38
- @error_name = error.class.name
39
- @error_message = error.message
40
- @error_debug_id = nil
41
- @error_details = nil
54
+ #
55
+ # Raised when a network raised when executing the request
56
+ # List of network errors can be found in errors/network_error_builder.rb
57
+ #
58
+ class NetworkError < Error
59
+ def initialize(message = nil, request:, error:)
60
+ super(message)
61
+ @request = request
62
+ @response = nil
63
+ @error_name = error.class.name
64
+ @error_message = error.message
65
+ @error_debug_id = nil
66
+ @error_details = nil
67
+ @paypal_request_id = request.http_request["paypal-request-id"]
68
+ end
42
69
  end
43
- end
44
70
 
45
- # 400
46
- class BadRequestError < FailedRequest
47
- end
71
+ # 400
72
+ class BadRequest < FailedRequest
73
+ end
48
74
 
49
- # 401
50
- class UnauthorizedError < FailedRequest
51
- end
75
+ # 401
76
+ class Unauthorized < FailedRequest
77
+ end
52
78
 
53
- # 403
54
- class ForbiddenError < FailedRequest
55
- end
79
+ # 403
80
+ class Forbidden < FailedRequest
81
+ end
56
82
 
57
- # 404
58
- class NotFoundError < FailedRequest
59
- end
83
+ # 404
84
+ class NotFound < FailedRequest
85
+ end
60
86
 
61
- # 405
62
- class MethodNotAllowedError < FailedRequest
63
- end
87
+ # 405
88
+ class MethodNotAllowed < FailedRequest
89
+ end
64
90
 
65
- # 406
66
- class NotAcceptableError < FailedRequest
67
- end
91
+ # 406
92
+ class NotAcceptable < FailedRequest
93
+ end
68
94
 
69
- # 409
70
- class ConflictError < FailedRequest
71
- end
95
+ # 409
96
+ class Conflict < FailedRequest
97
+ end
72
98
 
73
- # 415
74
- class UnsupportedMediaTypeError < FailedRequest
75
- end
99
+ # 415
100
+ class UnsupportedMediaType < FailedRequest
101
+ end
76
102
 
77
- # 422
78
- class UnprocessableEntityError < FailedRequest
79
- end
103
+ # 422
104
+ class UnprocessableEntity < FailedRequest
105
+ end
80
106
 
81
- # 429
82
- class TooManyRequestsError < FailedRequest
83
- end
107
+ # 429
108
+ class TooManyRequests < FailedRequest
109
+ end
84
110
 
85
- # 5xx
86
- class FatalError < FailedRequest
87
- end
111
+ # 5xx
112
+ class FatalError < FailedRequest
113
+ end
88
114
 
89
- # 500
90
- class InternalServerError < FatalError
91
- end
115
+ # 500
116
+ class InternalServerError < FatalError
117
+ end
92
118
 
93
- # 503
94
- class ServiceUnavailableError < FatalError
119
+ # 503
120
+ class ServiceUnavailable < FatalError
121
+ end
95
122
  end
96
123
  end
@@ -7,26 +7,34 @@ module PaypalAPI
7
7
  # Builds PaypalAPI::FailedRequest error
8
8
  #
9
9
  class FailedRequestErrorBuilder
10
+ # Matchings for Net::HTTP response class to PaypalAPI::Error class
10
11
  RESPONSE_ERROR_MAP = {
11
- Net::HTTPBadRequest => BadRequestError, # 400
12
- Net::HTTPUnauthorized => UnauthorizedError, # 401
13
- Net::HTTPForbidden => ForbiddenError, # 403
14
- Net::HTTPNotFound => NotFoundError, # 404
15
- Net::HTTPMethodNotAllowed => MethodNotAllowedError, # 405
16
- Net::HTTPNotAcceptable => NotAcceptableError, # 406
17
- Net::HTTPConflict => ConflictError, # 409
18
- Net::HTTPUnsupportedMediaType => UnsupportedMediaTypeError, # 415
19
- Net::HTTPUnprocessableEntity => UnprocessableEntityError, # 422
20
- Net::HTTPTooManyRequests => TooManyRequestsError, # 429
21
- Net::HTTPInternalServerError => InternalServerError, # 500
22
- Net::HTTPServiceUnavailable => ServiceUnavailableError # 503
12
+ Net::HTTPBadRequest => Errors::BadRequest, # 400
13
+ Net::HTTPUnauthorized => Errors::Unauthorized, # 401
14
+ Net::HTTPForbidden => Errors::Forbidden, # 403
15
+ Net::HTTPNotFound => Errors::NotFound, # 404
16
+ Net::HTTPMethodNotAllowed => Errors::MethodNotAllowed, # 405
17
+ Net::HTTPNotAcceptable => Errors::NotAcceptable, # 406
18
+ Net::HTTPConflict => Errors::Conflict, # 409
19
+ Net::HTTPUnsupportedMediaType => Errors::UnsupportedMediaType, # 415
20
+ Net::HTTPUnprocessableEntity => Errors::UnprocessableEntity, # 422
21
+ Net::HTTPTooManyRequests => Errors::TooManyRequests, # 429
22
+ Net::HTTPInternalServerError => Errors::InternalServerError, # 500
23
+ Net::HTTPServiceUnavailable => Errors::ServiceUnavailable # 503
23
24
  }.freeze
24
25
 
25
26
  class << self
27
+ # Builds FailedRequestError instance
28
+ #
29
+ # @param request [Request] Original request
30
+ # @param response [Response] Original response
31
+ #
32
+ # @return [Errors::FailedRequestError] error object
33
+ #
26
34
  def call(request:, response:)
27
35
  http_response = response.http_response
28
36
  error_message = "#{http_response.code} #{http_response.message}"
29
- error_class = RESPONSE_ERROR_MAP.fetch(http_response.class, FailedRequest)
37
+ error_class = RESPONSE_ERROR_MAP.fetch(http_response.class, Errors::FailedRequest)
30
38
  error_class.new(error_message, response: response, request: request)
31
39
  end
32
40
  end
@@ -5,6 +5,7 @@ module PaypalAPI
5
5
  # Builds PaypalAPI::NetowrkError error
6
6
  #
7
7
  class NetworkErrorBuilder
8
+ # List of possible Network errors
8
9
  ERRORS = [
9
10
  EOFError,
10
11
  Errno::ECONNABORTED,
@@ -20,8 +21,15 @@ module PaypalAPI
20
21
  ].freeze
21
22
 
22
23
  class << self
24
+ # Builds NetworkError instance
25
+ #
26
+ # @param request [Request] Original request
27
+ # @param error [StandardError] Original error
28
+ #
29
+ # @return [Errors::NetworkError] Built NetworkError
30
+ #
23
31
  def call(request:, error:)
24
- NetworkError.new(error.message, request: request, error: error)
32
+ Errors::NetworkError.new(error.message, request: request, error: error)
25
33
  end
26
34
  end
27
35
  end
@@ -13,10 +13,30 @@ module PaypalAPI
13
13
  # - assigns content-type header
14
14
  #
15
15
  class Request
16
- attr_reader :client, :http_request
16
+ # @return [Client] Current PaypalAPI Client
17
+ attr_reader :client
18
+
19
+ # @return [Net::HTTPRequest] Generated Net::HTTPRequest
20
+ attr_reader :http_request
21
+
22
+ # @return [Time, nil] Time when request was sent
17
23
  attr_accessor :requested_at
18
24
 
19
25
  # rubocop:disable Metrics/ParameterLists
26
+
27
+ # Initializes Request object
28
+ #
29
+ # @param client [Client] PaypalAPI client
30
+ # @param request_type [Class] One of: Net::HTTP::Post, Net::HTTP::Get,
31
+ # Net::HTTP::Put, Net::HTTP::Patch, Net::HTTP::Delete
32
+ # @param path [String] Request path
33
+ #
34
+ # @param query [Hash, nil] Request query
35
+ # @param body [Hash, nil] Request body
36
+ # @param headers [Hash, nil] Request headers
37
+ #
38
+ # @return [Request] Request object
39
+ #
20
40
  def initialize(client, request_type, path, body: nil, query: nil, headers: nil)
21
41
  @client = client
22
42
  @http_request = build_http_request(request_type, path, body: body, query: query, headers: headers)
@@ -5,6 +5,7 @@ module PaypalAPI
5
5
  # Executes PaypalAPI::Request and returns PaypalAPI::Response or raises PaypalAPI::Error
6
6
  #
7
7
  class RequestExecutor
8
+ # List of Net::HTTP responses that must be retried
8
9
  RETRYABLE_RESPONSES = [
9
10
  Net::HTTPServerError, # 5xx
10
11
  Net::HTTPConflict, # 409
@@ -12,6 +13,13 @@ module PaypalAPI
12
13
  ].freeze
13
14
 
14
15
  class << self
16
+ #
17
+ # Executes prepared Request, handles retries and preparation of errors
18
+ #
19
+ # @param [Request] request
20
+ #
21
+ # @return [Response] Response
22
+ #
15
23
  def call(request)
16
24
  http_response = execute(request)
17
25
  response = Response.new(http_response, requested_at: request.requested_at)
@@ -7,8 +7,20 @@ module PaypalAPI
7
7
  # PaypalAPI::Response object
8
8
  #
9
9
  class Response
10
- attr_reader :http_response, :requested_at
10
+ # @return [Net::HTTP::Response] Original Net::HTTP::Response object
11
+ attr_reader :http_response
11
12
 
13
+ # @return [Time] Time when request was sent
14
+ attr_reader :requested_at
15
+
16
+ #
17
+ # Initializes Response object
18
+ #
19
+ # @param http_response [Net::HTTP::Response] original response
20
+ # @param requested_at [Time] Time when original response was requested
21
+ #
22
+ # @return [Response] Initialized Response object
23
+ #
12
24
  def initialize(http_response, requested_at:)
13
25
  @requested_at = requested_at
14
26
  @http_response = http_response
@@ -18,31 +30,43 @@ module PaypalAPI
18
30
  @body = nil
19
31
  end
20
32
 
33
+ # Parses JSON body if response body contains JSON or returns original
34
+ # http body string
35
+ #
36
+ # @return [Hash, String] Parsed response body (with symbolized keys)
21
37
  def body
22
38
  @body ||= json_response? ? parse_json(http_body) : http_body
23
39
  end
24
40
 
41
+ # @return [Integer] HTTP status as Integer
25
42
  def http_status
26
43
  @http_status ||= http_response.code.to_i
27
44
  end
28
45
 
46
+ # @return [Hash] HTTP headers as Hash
29
47
  def http_headers
30
48
  @http_headers ||= http_response.each_header.to_h
31
49
  end
32
50
 
51
+ # @return [String] Original http body
33
52
  def http_body
34
53
  @http_body ||= http_response.body
35
54
  end
36
55
 
56
+ # Takes specific key from body, returns nil if key not present in parsed body
37
57
  def [](key)
38
58
  body[key.to_sym] if body.is_a?(Hash)
39
59
  end
40
60
 
61
+ # Fetches specific key from body, raises error if key not exists
41
62
  def fetch(key)
42
63
  data = body.is_a?(Hash) ? body : {}
43
64
  data.fetch(key.to_sym)
44
65
  end
45
66
 
67
+ #
68
+ # Instance representation string. Default was overwritten to hide secrets
69
+ #
46
70
  def inspect
47
71
  "#<#{self.class.name} (#{http_response.code})>"
48
72
  end
data/lib/paypal-api.rb CHANGED
@@ -2,29 +2,102 @@
2
2
 
3
3
  #
4
4
  # PaypalAPI is a main gem module.
5
+ #
5
6
  # It can store global PaypalAPI::Client for easier access to APIs.
6
7
  #
7
- # For example:
8
- # # setup client in an initializer
9
- # PaypalAPI.client = PaypalAPI::Client.new(...)
8
+ # @example Initializing new global client
9
+ # PaypalAPI.client = PaypalAPI::Client.new(
10
+ # client_id: ENV.fetch('PAYPAL_CLIENT_ID'),
11
+ # client_secret: ENV.fetch('PAYPAL_CLIENT_SECRET'),
12
+ # live: false
13
+ # )
10
14
  #
11
- # # And then use anywhere
15
+ # # And then call any APIs without mentioning the client
12
16
  # PaypalAPI::Webhooks.list # or PaypalAPI.webhooks.list
13
17
  #
14
18
  module PaypalAPI
15
19
  class << self
20
+ # Sets client
16
21
  attr_writer :client
17
22
 
23
+ # @!macro [new] request
24
+ #
25
+ # @param path [String] Request path
26
+ # @param query [Hash, nil] Request query parameters
27
+ # @param body [Hash, nil] Request body parameters
28
+ # @param headers [Hash, nil] Request headers
29
+ #
30
+ # @return [Response] Response object
31
+ #
32
+
33
+ # @!method post(path, query: nil, body: nil, headers: nil)
34
+ #
35
+ # Executes POST http request
36
+ # @macro request
37
+ #
38
+ # @!method get(path, query: nil, body: nil, headers: nil)
39
+ #
40
+ # Executes GET http request
41
+ # @macro request
42
+ #
43
+ # @!method patch(path, query: nil, body: nil, headers: nil)
44
+ #
45
+ # Executes PATCH http request
46
+ # @macro request
47
+ #
48
+ # @!method put(path, query: nil, body: nil, headers: nil)
49
+ #
50
+ # Executes PUT http request
51
+ # @macro request
52
+
53
+ # @!method delete(path, query: nil, body: nil, headers: nil)
54
+ #
55
+ # Executes DELETE http request
56
+ # @macro request
57
+ #
18
58
  [:post, :get, :patch, :put, :delete].each do |method_name|
19
59
  define_method(method_name) do |path, query: nil, body: nil, headers: nil|
20
60
  client.public_send(method_name, path, query: query, body: body, headers: headers)
21
61
  end
22
62
  end
23
63
 
64
+ #
65
+ # @!method authentication
66
+ # @return [Authentication]
67
+ #
68
+ # @!method authorized_payments
69
+ # @return [AuthorizedPayments]
70
+ #
71
+ # @!method captured_payments
72
+ # @return [CapturedPayments]
73
+ #
74
+ # @!method catalog_products
75
+ # @return [CatalogProducts]
76
+ #
77
+ # @!method orders
78
+ # @return [Orders]
79
+ #
80
+ # @!method refunds
81
+ # @return [Refunds]
82
+ #
83
+ # @!method shipment_tracking
84
+ # @return [ShipmentTracking]
85
+ #
86
+ # @!method subscriptions
87
+ # @return [Subscriptions]
88
+ #
89
+ # @!method webhooks
90
+ # @return [Webhooks]
91
+ #
24
92
  %i[
25
- authorization
93
+ authentication
94
+ authorized_payments
95
+ captured_payments
96
+ catalog_products
26
97
  orders
27
- payments
98
+ refunds
99
+ shipment_tracking
100
+ subscriptions
28
101
  webhooks
29
102
  ].each do |method_name|
30
103
  define_method(method_name) do
@@ -32,6 +105,7 @@ module PaypalAPI
32
105
  end
33
106
  end
34
107
 
108
+ # Globally set Client object
35
109
  def client
36
110
  raise "#{name}.client must be set" unless @client
37
111
 
@@ -41,8 +115,8 @@ module PaypalAPI
41
115
  end
42
116
 
43
117
  require_relative "paypal-api/access_token"
118
+ require_relative "paypal-api/api_collection"
44
119
  require_relative "paypal-api/client"
45
- require_relative "paypal-api/collection"
46
120
  require_relative "paypal-api/config"
47
121
  require_relative "paypal-api/error"
48
122
  require_relative "paypal-api/failed_request_error_builder"
@@ -50,7 +124,12 @@ require_relative "paypal-api/network_error_builder"
50
124
  require_relative "paypal-api/request"
51
125
  require_relative "paypal-api/request_executor"
52
126
  require_relative "paypal-api/response"
53
- require_relative "paypal-api/collections/authentication"
54
- require_relative "paypal-api/collections/orders"
55
- require_relative "paypal-api/collections/payments"
56
- require_relative "paypal-api/collections/webhooks"
127
+ require_relative "paypal-api/api_collections/authentication"
128
+ require_relative "paypal-api/api_collections/authorized_payments"
129
+ require_relative "paypal-api/api_collections/captured_payments"
130
+ require_relative "paypal-api/api_collections/catalog_products"
131
+ require_relative "paypal-api/api_collections/orders"
132
+ require_relative "paypal-api/api_collections/refunds"
133
+ require_relative "paypal-api/api_collections/shipment_tracking"
134
+ require_relative "paypal-api/api_collections/subscriptions"
135
+ require_relative "paypal-api/api_collections/webhooks"
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.0.1
4
+ version: 0.0.3
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-06 00:00:00.000000000 Z
11
+ date: 2024-08-12 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: PayPal REST API with no dependencies.
14
14
  email:
@@ -21,12 +21,17 @@ files:
21
21
  - VERSION
22
22
  - lib/paypal-api.rb
23
23
  - lib/paypal-api/access_token.rb
24
+ - lib/paypal-api/api_collection.rb
25
+ - lib/paypal-api/api_collections/authentication.rb
26
+ - lib/paypal-api/api_collections/authorized_payments.rb
27
+ - lib/paypal-api/api_collections/captured_payments.rb
28
+ - lib/paypal-api/api_collections/catalog_products.rb
29
+ - lib/paypal-api/api_collections/orders.rb
30
+ - lib/paypal-api/api_collections/refunds.rb
31
+ - lib/paypal-api/api_collections/shipment_tracking.rb
32
+ - lib/paypal-api/api_collections/subscriptions.rb
33
+ - lib/paypal-api/api_collections/webhooks.rb
24
34
  - lib/paypal-api/client.rb
25
- - lib/paypal-api/collection.rb
26
- - lib/paypal-api/collections/authentication.rb
27
- - lib/paypal-api/collections/orders.rb
28
- - lib/paypal-api/collections/payments.rb
29
- - lib/paypal-api/collections/webhooks.rb
30
35
  - lib/paypal-api/config.rb
31
36
  - lib/paypal-api/error.rb
32
37
  - lib/paypal-api/failed_request_error_builder.rb
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module PaypalAPI
4
- #
5
- # Create, update, retrieve, authorize, and capture orders.
6
- #
7
- # https://developer.paypal.com/docs/api/orders/v2/
8
- #
9
- class Orders < Collection
10
- module APIs
11
- #
12
- # @see https://developer.paypal.com/docs/api/orders/v2/#orders_authorize
13
- #
14
- def authorize(id, query: nil, body: nil, headers: nil)
15
- client.post("/v2/checkout/orders/#{id}/authorize", query: query, body: body, headers: headers)
16
- end
17
-
18
- #
19
- # @see https://developer.paypal.com/docs/api/orders/v2/#orders_create
20
- #
21
- def create(query: nil, body: nil, headers: nil)
22
- client.post("/v2/checkout/orders", query: query, body: body, headers: headers)
23
- end
24
-
25
- #
26
- # @see https://developer.paypal.com/docs/api/orders/v2/#orders_get
27
- #
28
- def show(id, query: nil, body: nil, headers: nil)
29
- client.get("/v2/checkout/orders/#{id}", query: query, body: body, headers: headers)
30
- end
31
- end
32
-
33
- include APIs
34
- extend APIs
35
- end
36
- end
@@ -1,51 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module PaypalAPI
4
- #
5
- # Use in conjunction with the Orders API to authorize payments, capture authorized payments,
6
- # refund payments that have already been captured, and show payment information.
7
- #
8
- # https://developer.paypal.com/docs/api/payments/v2
9
- #
10
- class Payments < Collection
11
- module APIs
12
- #
13
- # @see https://developer.paypal.com/docs/api/payments/v2/#authorizations_capture
14
- #
15
- def capture(authorization_id, query: nil, body: nil, headers: nil)
16
- client.post("/v2/payments/authorizations/#{authorization_id}/capture", query: query, body: body, headers: headers)
17
- end
18
-
19
- #
20
- # @see https://developer.paypal.com/docs/api/payments/v2/#captures_refund
21
- #
22
- def refund(capture_id, query: nil, body: nil, headers: nil)
23
- client.post("/v2/payments/captures/#{capture_id}/refund", query: query, body: body, headers: headers)
24
- end
25
-
26
- #
27
- # @see https://developer.paypal.com/docs/api/payments/v2/#authorizations_get
28
- #
29
- def show_authorized(authorization_id, query: nil, body: nil, headers: nil)
30
- client.get("/v2/payments/authorizations/#{authorization_id}", query: query, body: body, headers: headers)
31
- end
32
-
33
- #
34
- # @see https://developer.paypal.com/docs/api/payments/v2/#captures_get
35
- #
36
- def show_captured(capture_id, query: nil, body: nil, headers: nil)
37
- client.get("/v2/payments/captures/#{capture_id}", query: query, body: body, headers: headers)
38
- end
39
-
40
- #
41
- # @see https://developer.paypal.com/docs/api/payments/v2/#authorizations_void
42
- #
43
- def void(authorization_id, query: nil, body: nil, headers: nil)
44
- client.post("/v2/payments/authorizations/#{authorization_id}/void", query: query, body: body, headers: headers)
45
- end
46
- end
47
-
48
- include APIs
49
- extend APIs
50
- end
51
- end