acquiring-sdk-ruby 0.1.0

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.
Files changed (174) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +2 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +140 -0
  5. data/Rakefile +34 -0
  6. data/acquiring-sdk-ruby.gemspec +30 -0
  7. data/lib/worldline/acquiring/sdk/api_resource.rb +53 -0
  8. data/lib/worldline/acquiring/sdk/authentication/authenticator.rb +21 -0
  9. data/lib/worldline/acquiring/sdk/authentication/authorization_type.rb +17 -0
  10. data/lib/worldline/acquiring/sdk/authentication/oauth2_authenticator.rb +142 -0
  11. data/lib/worldline/acquiring/sdk/authentication/oauth2_exception.rb +15 -0
  12. data/lib/worldline/acquiring/sdk/authentication.rb +1 -0
  13. data/lib/worldline/acquiring/sdk/call_context.rb +9 -0
  14. data/lib/worldline/acquiring/sdk/client.rb +69 -0
  15. data/lib/worldline/acquiring/sdk/communication/communication_exception.rb +21 -0
  16. data/lib/worldline/acquiring/sdk/communication/connection.rb +50 -0
  17. data/lib/worldline/acquiring/sdk/communication/default_connection.rb +429 -0
  18. data/lib/worldline/acquiring/sdk/communication/metadata_provider.rb +162 -0
  19. data/lib/worldline/acquiring/sdk/communication/multipart_form_data_object.rb +54 -0
  20. data/lib/worldline/acquiring/sdk/communication/multipart_form_data_request.rb +15 -0
  21. data/lib/worldline/acquiring/sdk/communication/not_found_exception.rb +21 -0
  22. data/lib/worldline/acquiring/sdk/communication/param_request.rb +16 -0
  23. data/lib/worldline/acquiring/sdk/communication/pooled_connection.rb +28 -0
  24. data/lib/worldline/acquiring/sdk/communication/request_header.rb +64 -0
  25. data/lib/worldline/acquiring/sdk/communication/request_param.rb +30 -0
  26. data/lib/worldline/acquiring/sdk/communication/response_exception.rb +58 -0
  27. data/lib/worldline/acquiring/sdk/communication/response_header.rb +80 -0
  28. data/lib/worldline/acquiring/sdk/communication.rb +1 -0
  29. data/lib/worldline/acquiring/sdk/communicator.rb +506 -0
  30. data/lib/worldline/acquiring/sdk/communicator_configuration.rb +197 -0
  31. data/lib/worldline/acquiring/sdk/domain/data_object.rb +34 -0
  32. data/lib/worldline/acquiring/sdk/domain/shopping_cart_extension.rb +62 -0
  33. data/lib/worldline/acquiring/sdk/domain/uploadable_file.rb +35 -0
  34. data/lib/worldline/acquiring/sdk/domain.rb +1 -0
  35. data/lib/worldline/acquiring/sdk/factory.rb +183 -0
  36. data/lib/worldline/acquiring/sdk/json/default_marshaller.rb +36 -0
  37. data/lib/worldline/acquiring/sdk/json/marshaller.rb +29 -0
  38. data/lib/worldline/acquiring/sdk/json/marshaller_syntax_exception.rb +11 -0
  39. data/lib/worldline/acquiring/sdk/json.rb +1 -0
  40. data/lib/worldline/acquiring/sdk/logging/communicator_logger.rb +26 -0
  41. data/lib/worldline/acquiring/sdk/logging/log_message_builder.rb +91 -0
  42. data/lib/worldline/acquiring/sdk/logging/logging_capable.rb +19 -0
  43. data/lib/worldline/acquiring/sdk/logging/obfuscation/body_obfuscator.rb +101 -0
  44. data/lib/worldline/acquiring/sdk/logging/obfuscation/header_obfuscator.rb +54 -0
  45. data/lib/worldline/acquiring/sdk/logging/obfuscation/obfuscation_capable.rb +23 -0
  46. data/lib/worldline/acquiring/sdk/logging/obfuscation/obfuscation_rule.rb +49 -0
  47. data/lib/worldline/acquiring/sdk/logging/obfuscation.rb +1 -0
  48. data/lib/worldline/acquiring/sdk/logging/request_log_message_builder.rb +52 -0
  49. data/lib/worldline/acquiring/sdk/logging/response_log_message_builder.rb +43 -0
  50. data/lib/worldline/acquiring/sdk/logging/ruby_communicator_logger.rb +63 -0
  51. data/lib/worldline/acquiring/sdk/logging/stdout_communicator_logger.rb +33 -0
  52. data/lib/worldline/acquiring/sdk/logging.rb +1 -0
  53. data/lib/worldline/acquiring/sdk/proxy_configuration.rb +76 -0
  54. data/lib/worldline/acquiring/sdk/v1/acquirer/acquirer_client.rb +35 -0
  55. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/accountverifications/account_verifications_client.rb +60 -0
  56. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/accountverifications.rb +4 -0
  57. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/dynamiccurrencyconversion/dynamic_currency_conversion_client.rb +60 -0
  58. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/dynamiccurrencyconversion.rb +4 -0
  59. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/merchant_client.rb +66 -0
  60. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/payments/get_payment_status_params.rb +34 -0
  61. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/payments/payments_client.rb +224 -0
  62. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/payments.rb +4 -0
  63. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/refunds/get_refund_params.rb +34 -0
  64. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/refunds/refunds_client.rb +157 -0
  65. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/refunds.rb +4 -0
  66. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/technicalreversals/technical_reversals_client.rb +64 -0
  67. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant/technicalreversals.rb +4 -0
  68. data/lib/worldline/acquiring/sdk/v1/acquirer/merchant.rb +4 -0
  69. data/lib/worldline/acquiring/sdk/v1/acquirer.rb +4 -0
  70. data/lib/worldline/acquiring/sdk/v1/api_exception.rb +63 -0
  71. data/lib/worldline/acquiring/sdk/v1/authorization_exception.rb +23 -0
  72. data/lib/worldline/acquiring/sdk/v1/domain/address_verification_data.rb +41 -0
  73. data/lib/worldline/acquiring/sdk/v1/domain/amount_data.rb +48 -0
  74. data/lib/worldline/acquiring/sdk/v1/domain/api_account_verification_request.rb +70 -0
  75. data/lib/worldline/acquiring/sdk/v1/domain/api_account_verification_response.rb +87 -0
  76. data/lib/worldline/acquiring/sdk/v1/domain/api_action_response.rb +71 -0
  77. data/lib/worldline/acquiring/sdk/v1/domain/api_action_response_for_refund.rb +71 -0
  78. data/lib/worldline/acquiring/sdk/v1/domain/api_capture_request.rb +75 -0
  79. data/lib/worldline/acquiring/sdk/v1/domain/api_capture_request_for_refund.rb +43 -0
  80. data/lib/worldline/acquiring/sdk/v1/domain/api_increment_request.rb +61 -0
  81. data/lib/worldline/acquiring/sdk/v1/domain/api_increment_response.rb +43 -0
  82. data/lib/worldline/acquiring/sdk/v1/domain/api_payment_error_response.rb +62 -0
  83. data/lib/worldline/acquiring/sdk/v1/domain/api_payment_refund_request.rb +77 -0
  84. data/lib/worldline/acquiring/sdk/v1/domain/api_payment_request.rb +95 -0
  85. data/lib/worldline/acquiring/sdk/v1/domain/api_payment_resource.rb +103 -0
  86. data/lib/worldline/acquiring/sdk/v1/domain/api_payment_response.rb +126 -0
  87. data/lib/worldline/acquiring/sdk/v1/domain/api_payment_reversal_request.rb +61 -0
  88. data/lib/worldline/acquiring/sdk/v1/domain/api_payment_summary_for_response.rb +66 -0
  89. data/lib/worldline/acquiring/sdk/v1/domain/api_references_for_responses.rb +48 -0
  90. data/lib/worldline/acquiring/sdk/v1/domain/api_refund_request.rb +88 -0
  91. data/lib/worldline/acquiring/sdk/v1/domain/api_refund_resource.rb +110 -0
  92. data/lib/worldline/acquiring/sdk/v1/domain/api_refund_response.rb +133 -0
  93. data/lib/worldline/acquiring/sdk/v1/domain/api_refund_summary_for_response.rb +66 -0
  94. data/lib/worldline/acquiring/sdk/v1/domain/api_reversal_response.rb +36 -0
  95. data/lib/worldline/acquiring/sdk/v1/domain/api_technical_reversal_request.rb +50 -0
  96. data/lib/worldline/acquiring/sdk/v1/domain/api_technical_reversal_response.rb +62 -0
  97. data/lib/worldline/acquiring/sdk/v1/domain/card_data_for_dcc.rb +48 -0
  98. data/lib/worldline/acquiring/sdk/v1/domain/card_on_file_data.rb +52 -0
  99. data/lib/worldline/acquiring/sdk/v1/domain/card_payment_data.rb +114 -0
  100. data/lib/worldline/acquiring/sdk/v1/domain/card_payment_data_for_refund.rb +82 -0
  101. data/lib/worldline/acquiring/sdk/v1/domain/card_payment_data_for_resource.rb +43 -0
  102. data/lib/worldline/acquiring/sdk/v1/domain/card_payment_data_for_response.rb +52 -0
  103. data/lib/worldline/acquiring/sdk/v1/domain/card_payment_data_for_verification.rb +91 -0
  104. data/lib/worldline/acquiring/sdk/v1/domain/dcc_data.rb +55 -0
  105. data/lib/worldline/acquiring/sdk/v1/domain/dcc_proposal.rb +60 -0
  106. data/lib/worldline/acquiring/sdk/v1/domain/e_commerce_data.rb +52 -0
  107. data/lib/worldline/acquiring/sdk/v1/domain/e_commerce_data_for_account_verification.rb +45 -0
  108. data/lib/worldline/acquiring/sdk/v1/domain/e_commerce_data_for_response.rb +41 -0
  109. data/lib/worldline/acquiring/sdk/v1/domain/get_dcc_rate_request.rb +75 -0
  110. data/lib/worldline/acquiring/sdk/v1/domain/get_dcc_rate_response.rb +57 -0
  111. data/lib/worldline/acquiring/sdk/v1/domain/initial_card_on_file_data.rb +41 -0
  112. data/lib/worldline/acquiring/sdk/v1/domain/merchant_data.rb +76 -0
  113. data/lib/worldline/acquiring/sdk/v1/domain/network_token_data.rb +41 -0
  114. data/lib/worldline/acquiring/sdk/v1/domain/payment_references.rb +48 -0
  115. data/lib/worldline/acquiring/sdk/v1/domain/plain_card_data.rb +48 -0
  116. data/lib/worldline/acquiring/sdk/v1/domain/point_of_sale_data.rb +34 -0
  117. data/lib/worldline/acquiring/sdk/v1/domain/point_of_sale_data_for_dcc.rb +41 -0
  118. data/lib/worldline/acquiring/sdk/v1/domain/rate_data.rb +64 -0
  119. data/lib/worldline/acquiring/sdk/v1/domain/sub_operation.rb +94 -0
  120. data/lib/worldline/acquiring/sdk/v1/domain/sub_operation_for_refund.rb +87 -0
  121. data/lib/worldline/acquiring/sdk/v1/domain/subsequent_card_on_file_data.rb +48 -0
  122. data/lib/worldline/acquiring/sdk/v1/domain/three_d_secure.rb +62 -0
  123. data/lib/worldline/acquiring/sdk/v1/domain/transaction_data_for_dcc.rb +52 -0
  124. data/lib/worldline/acquiring/sdk/v1/domain.rb +4 -0
  125. data/lib/worldline/acquiring/sdk/v1/exception_factory.rb +48 -0
  126. data/lib/worldline/acquiring/sdk/v1/ping/ping_client.rb +52 -0
  127. data/lib/worldline/acquiring/sdk/v1/ping.rb +4 -0
  128. data/lib/worldline/acquiring/sdk/v1/platform_exception.rb +23 -0
  129. data/lib/worldline/acquiring/sdk/v1/reference_exception.rb +23 -0
  130. data/lib/worldline/acquiring/sdk/v1/v1_client.rb +43 -0
  131. data/lib/worldline/acquiring/sdk/v1/validation_exception.rb +23 -0
  132. data/lib/worldline/acquiring/sdk/v1.rb +4 -0
  133. data/lib/worldline/acquiring/sdk.rb +1 -0
  134. data/spec/comparable_extension.rb +29 -0
  135. data/spec/fixtures/resources/authentication/oauth2AccessToken.expired.json +4 -0
  136. data/spec/fixtures/resources/authentication/oauth2AccessToken.invalidClient.json +4 -0
  137. data/spec/fixtures/resources/authentication/oauth2AccessToken.json +4 -0
  138. data/spec/fixtures/resources/communication/getWithQueryParams.json +3 -0
  139. data/spec/fixtures/resources/communication/getWithoutQueryParams.json +3 -0
  140. data/spec/fixtures/resources/communication/notFound.html +1 -0
  141. data/spec/fixtures/resources/communication/postWithBadRequestResponse.json +11 -0
  142. data/spec/fixtures/resources/communication/postWithCreatedResponse.json +6 -0
  143. data/spec/fixtures/resources/communication/unknownServerError.json +10 -0
  144. data/spec/fixtures/resources/logging/bodyNoObfuscation.json +7 -0
  145. data/spec/fixtures/resources/logging/bodyWithBinObfuscated.json +3 -0
  146. data/spec/fixtures/resources/logging/bodyWithBinOriginal.json +3 -0
  147. data/spec/fixtures/resources/logging/bodyWithCardCustomObfuscated.json +13 -0
  148. data/spec/fixtures/resources/logging/bodyWithCardObfuscated.json +13 -0
  149. data/spec/fixtures/resources/logging/bodyWithCardOriginal.json +13 -0
  150. data/spec/fixtures/resources/logging/bodyWithObjectObfuscated.json +5 -0
  151. data/spec/fixtures/resources/logging/bodyWithObjectOriginal.json +5 -0
  152. data/spec/fixtures/resources/properties.oauth2.yml +8 -0
  153. data/spec/fixtures/resources/properties.proxy.yml +14 -0
  154. data/spec/integration/connection_pooling_spec.rb +74 -0
  155. data/spec/integration/multipart_form_data_spec.rb +216 -0
  156. data/spec/integration/process_payment_spec.rb +43 -0
  157. data/spec/integration/request_dcc_rate_spec.rb +24 -0
  158. data/spec/integration/sdk_proxy_spec.rb +70 -0
  159. data/spec/integration_setup.rb +111 -0
  160. data/spec/lib/authentication/oauth2_authenticator_spec.rb +68 -0
  161. data/spec/lib/client_spec.rb +47 -0
  162. data/spec/lib/communication/default_connection_logger_spec.rb +484 -0
  163. data/spec/lib/communication/default_connection_spec.rb +352 -0
  164. data/spec/lib/communication/metadata_provider_spec.rb +93 -0
  165. data/spec/lib/communicator_configuration_spec.rb +181 -0
  166. data/spec/lib/communicator_spec.rb +34 -0
  167. data/spec/lib/factory_spec.rb +38 -0
  168. data/spec/lib/json/default_marshaller_spec.rb +39 -0
  169. data/spec/lib/logging/obfuscation/body_obfuscator_spec.rb +86 -0
  170. data/spec/lib/logging/obfuscation/header_obfuscator_spec.rb +100 -0
  171. data/spec/lib/logging/ruby_communicator_logger_spec.rb +92 -0
  172. data/spec/lib/logging/stdout_communicator_logger_spec.rb +64 -0
  173. data/spec/spec_helper.rb +32 -0
  174. metadata +375 -0
@@ -0,0 +1,506 @@
1
+ require 'securerandom'
2
+ require 'uri'
3
+ require 'worldline/acquiring/sdk/communication/communication_exception'
4
+ require 'worldline/acquiring/sdk/communication/multipart_form_data_object'
5
+ require 'worldline/acquiring/sdk/communication/multipart_form_data_request'
6
+ require 'worldline/acquiring/sdk/communication/not_found_exception'
7
+ require 'worldline/acquiring/sdk/communication/pooled_connection'
8
+ require 'worldline/acquiring/sdk/communication/request_header'
9
+ require 'worldline/acquiring/sdk/communication/response_exception'
10
+ require 'worldline/acquiring/sdk/communication/response_header'
11
+ require 'worldline/acquiring/sdk/logging/logging_capable'
12
+ require 'worldline/acquiring/sdk/logging/obfuscation/obfuscation_capable'
13
+
14
+ module Worldline
15
+ module Acquiring
16
+ module SDK
17
+ # Class responsible for facilitating communication with the Worldline Acquiring platform.
18
+ # It combines the following classes to provide communication functionality:
19
+ #
20
+ # api_endpoint:: the base URL to the Worldline Acquiring platform
21
+ # connection:: {Worldline::Acquiring::SDK::Communication::Connection} used to communicate with the Worldline Acquiring platform
22
+ # authenticator:: {Worldline::Acquiring::SDK::Authentication::Authenticator} used for authenticating messages sent
23
+ # metadata_provider:: {Worldline::Acquiring::SDK::Communication::MetadataProvider} object containing information relevant for sending requests
24
+ # marshaller:: {Worldline::Acquiring::SDK::JSON::Marshaller} that is used to marshal and unmarshal data to and from JSON format
25
+ #
26
+ # @attr_reader [Worldline::Acquiring::SDK::JSON::Marshaller] marshaller A Marshaller instance used by the communicator for serializing/deserializing to/from JSON
27
+ #
28
+ class Communicator
29
+ include Logging::LoggingCapable
30
+ include Logging::Obfuscation::ObfuscationCapable
31
+
32
+ # Creates a new Communicator.
33
+ #
34
+ # @param api_endpoint [String] the base URL to the Worldline Acquiring platform
35
+ # @param connection [Worldline::Acquiring::SDK::Communication::Connection] used to communicate with the Worldline Acquiring platform
36
+ # @param authenticator [Worldline::Acquiring::SDK::Authentication::Authenticator] used for authenticating messages sent
37
+ # @param metadata_provider [Worldline::Acquiring::SDK::Communication::MetadataProvider] object containing information relevant for sending requests
38
+ # @param marshaller [Worldline::Acquiring::SDK::JSON::Marshaller] used to marshal and unmarshal data to and from JSON format
39
+ #
40
+ def initialize(api_endpoint, connection, authenticator, metadata_provider, marshaller)
41
+ raise ArgumentError.new('api_endpoint is required') unless api_endpoint
42
+ raise ArgumentError.new('connection is required') unless connection
43
+ raise ArgumentError.new('authenticator is required') unless authenticator
44
+ raise ArgumentError.new('metadata_provider is required') unless metadata_provider
45
+ raise ArgumentError('marshaller is required') if marshaller.nil?
46
+
47
+ uri = URI(api_endpoint)
48
+ raise RuntimeError('api_endpoint should not contain a path') unless uri.path.nil? || uri.path.empty?
49
+ unless uri.userinfo.nil? && uri.query.nil? && uri.fragment.nil?
50
+ raise RuntimeError('api_endpoint should not contain user info, query or fragment')
51
+ end
52
+ @api_endpoint = uri
53
+ @connection = connection
54
+ @authenticator = authenticator
55
+ @metadata_provider = metadata_provider
56
+ @marshaller = marshaller
57
+ end
58
+
59
+ # Performs a GET request to the Worldline Acquiring platform and returns the response as the given response type.
60
+ #
61
+ # @param relative_path [String] path relative to the API endpoint
62
+ # @param request_headers [Array<Worldline::Acquiring::SDK::Communication::RequestHeader>, nil] optional array of request headers
63
+ # @param request_parameters [Worldline::Acquiring::SDK::Communication::ParamRequest, nil] optional request parameters
64
+ # @param response_type [Type] the response type.
65
+ # @param context [Worldline::Acquiring::SDK::CallContext, nil] optional call context.
66
+ # @return the response of the GET request as the given response type
67
+ # @raise [Worldline::Acquiring::SDK::Communication::ResponseException] if the request could not be fulfilled successfully.
68
+ # This occurs for example if the request is not authenticated correctly
69
+ # @raise [Worldline::Acquiring::SDK::Communication::NotFoundException] if the requested resource is not found
70
+ # @raise [Worldline::Acquiring::SDK::Communication::CommunicationException] if there is an error in communicating with the Worldline Acquiring platform.
71
+ # This occurs for example if a timeout occurs.
72
+ def get(relative_path, request_headers, request_parameters, response_type, context)
73
+ request_parameter_list = request_parameters && request_parameters.to_request_parameters
74
+ uri = to_absolute_uri(relative_path, request_parameter_list)
75
+
76
+ request_headers = [] if request_headers.nil?
77
+ add_generic_headers('GET', uri, request_headers, context)
78
+
79
+ response_status_code, response_headers, response_body = nil
80
+ @connection.get(uri, request_headers) do |status_code, headers, content|
81
+ response_status_code = status_code
82
+ response_headers = headers
83
+ response_body = content.read.force_encoding('UTF-8')
84
+ end
85
+ process_response(response_body, response_status_code, response_headers, response_type, relative_path, context)
86
+ end
87
+
88
+ # Performs a GET request to the Worldline Acquiring platform and yields the response as the headers and body.
89
+ #
90
+ # @param relative_path [String] Path relative to the API endpoint
91
+ # @param request_headers [Array<Worldline::Acquiring::SDK::Communication::RequestHeader>, nil] Optional array of request headers
92
+ # @param request_parameters [Worldline::Acquiring::SDK::Communication::ParamRequest, nil] Optional request parameters
93
+ # @param context [Worldline::Acquiring::SDK::CallContext, nil] Optional call context.
94
+ # @yield [Array<Worldline::Acquiring::SDK::Communication::ResponseHeader>, IO] The response headers and body.
95
+ # @raise [Worldline::Acquiring::SDK::Communication::ResponseException] if the request could not be fulfilled successfully.
96
+ # This occurs for example if the request is not authenticated correctly
97
+ # @raise [Worldline::Acquiring::SDK::Communication::NotFoundException] if the requested resource is not found
98
+ # @raise [Worldline::Acquiring::SDK::Communication::CommunicationException] if there is an error in communicating with the Worldline Acquiring platform.
99
+ # This occurs for example if a timeout occurs.
100
+ def get_with_binary_response(relative_path, request_headers, request_parameters, context)
101
+ request_parameter_list = request_parameters && request_parameters.to_request_parameters
102
+ uri = to_absolute_uri(relative_path, request_parameter_list)
103
+
104
+ request_headers = [] if request_headers.nil?
105
+ add_generic_headers('GET', uri, request_headers, context)
106
+
107
+ response_status_code, response_headers, response_body = nil
108
+ @connection.get(uri, request_headers) do |status_code, headers, content|
109
+ response_status_code = status_code
110
+ response_headers = headers
111
+ response_body = process_binary_response(status_code, content, headers, context) do |h, c|
112
+ yield h, c
113
+ end
114
+ end
115
+ throw_exception_if_necessary(response_body, response_status_code, response_headers, relative_path)
116
+ end
117
+
118
+ # Performs a DELETE request to the Worldline Acquiring platform and returns the response as the given response type.
119
+ #
120
+ # @param relative_path [String] Path relative to the API endpoint
121
+ # @param request_headers [Array<Worldline::Acquiring::SDK::Communication::RequestHeader>, nil] Optional array of request headers
122
+ # @param request_parameters [Worldline::Acquiring::SDK::Communication::ParamRequest, nil] Optional request parameters
123
+ # @param response_type [Type] The response type.
124
+ # @param context [Worldline::Acquiring::SDK::CallContext, nil] Optional call context.
125
+ # @return The response of the DELETE request as the given response type
126
+ # @raise [Worldline::Acquiring::SDK::Communication::ResponseException] if the request could not be fulfilled successfully.
127
+ # This occurs for example if the request is not authenticated correctly
128
+ # @raise [Worldline::Acquiring::SDK::Communication::NotFoundException] if the requested resource is not found
129
+ # @raise [Worldline::Acquiring::SDK::Communication::CommunicationException] if there is an error in communicating with the Worldline Acquiring platform.
130
+ # This occurs for example if a timeout occurs.
131
+ def delete(relative_path, request_headers, request_parameters, response_type, context)
132
+ request_parameter_list = request_parameters && request_parameters.to_request_parameters
133
+ uri = to_absolute_uri(relative_path, request_parameter_list)
134
+ request_headers = [] if request_headers.nil?
135
+ add_generic_headers('DELETE', uri, request_headers, context)
136
+
137
+ response_status_code, response_headers, response_body = nil
138
+ @connection.delete(uri, request_headers) do |status_code, headers, content|
139
+ response_status_code = status_code
140
+ response_headers = headers
141
+ response_body = content.read.force_encoding('UTF-8')
142
+ end
143
+ process_response(response_body, response_status_code, response_headers, response_type, relative_path, context)
144
+ end
145
+
146
+ # Performs a DELETE request to the Worldline Acquiring platform and yields the response as the headers and body.
147
+ #
148
+ # @param relative_path [String] Path relative to the API endpoint
149
+ # @param request_headers [Array<Worldline::Acquiring::SDK::Communication::RequestHeader>, nil] Optional array of request headers
150
+ # @param request_parameters [Worldline::Acquiring::SDK::Communication::ParamRequest, nil] Optional request parameters
151
+ # @param context [Worldline::Acquiring::SDK::CallContext, nil] Optional call context.
152
+ # @yield [Array<Worldline::Acquiring::SDK::Communication::ResponseHeader>, IO] The response headers and body.
153
+ # @raise [Worldline::Acquiring::SDK::Communication::ResponseException] if the request could not be fulfilled successfully.
154
+ # This occurs for example if the request is not authenticated correctly
155
+ # @raise [Worldline::Acquiring::SDK::Communication::NotFoundException] if the requested resource is not found
156
+ # @raise [Worldline::Acquiring::SDK::Communication::CommunicationException] if there is an error in communicating with the Worldline Acquiring platform.
157
+ # This occurs for example if a timeout occurs.
158
+ def delete_with_binary_response(relative_path, request_headers, request_parameters, context)
159
+ request_parameter_list = request_parameters && request_parameters.to_request_parameters
160
+ uri = to_absolute_uri(relative_path, request_parameter_list)
161
+ request_headers = [] if request_headers.nil?
162
+ add_generic_headers('DELETE', uri, request_headers, context)
163
+
164
+ response_status_code, response_headers, response_body = nil
165
+ @connection.delete(uri, request_headers) do |status_code, headers, content|
166
+ response_status_code = status_code
167
+ response_headers = headers
168
+ response_body = process_binary_response(status_code, content, headers, context) do |h, c|
169
+ yield h, c
170
+ end
171
+ end
172
+ throw_exception_if_necessary(response_body, response_status_code, response_headers, relative_path)
173
+ end
174
+
175
+ # Performs a POST request to the Worldline Acquiring platform and returns the response as the given response type.
176
+ #
177
+ # @param relative_path [String] Path relative to the API endpoint
178
+ # @param request_headers [Array<Worldline::Acquiring::SDK::Communication::RequestHeader>, nil] Optional array of request headers
179
+ # @param request_parameters [Worldline::Acquiring::SDK::Communication::ParamRequest, nil] Optional request parameters
180
+ # @param request_body [Worldline::Acquiring::SDK::Domain::DataObject, Worldline::Acquiring::SDK::Communication::MultipartFormDataObject, Worldline::Acquiring::SDK::Communication::MultipartFormDataRequest, nil]
181
+ # The optional request body
182
+ # @param response_type [Type] The response type.
183
+ # @param context [Worldline::Acquiring::SDK::CallContext, nil] Optional call context.
184
+ # @return The response of the POST request as the given response type
185
+ # @raise [Worldline::Acquiring::SDK::Communication::ResponseException] if the request could not be fulfilled successfully.
186
+ # This occurs for example if the request is not authenticated correctly
187
+ # @raise [Worldline::Acquiring::SDK::Communication::NotFoundException] if the requested resource is not found
188
+ # @raise [Worldline::Acquiring::SDK::Communication::CommunicationException] if there is an error in communicating with the Worldline Acquiring platform.
189
+ # This occurs for example if a timeout occurs.
190
+ def post(relative_path, request_headers, request_parameters, request_body, response_type, context)
191
+ request_parameter_list = request_parameters && request_parameters.to_request_parameters
192
+ uri = to_absolute_uri(relative_path, request_parameter_list)
193
+ request_headers = [] if request_headers.nil?
194
+
195
+ body = nil
196
+ if request_body.is_a? Communication::MultipartFormDataObject
197
+ request_headers.push(Communication::RequestHeader.new('Content-Type', request_body.content_type))
198
+ body = request_body
199
+ elsif request_body.is_a? Communication::MultipartFormDataRequest
200
+ multipart = request_body.to_multipart_form_data_object
201
+ request_headers.push(Communication::RequestHeader.new('Content-Type', multipart.content_type))
202
+ body = multipart
203
+ elsif !request_body.nil?
204
+ request_headers.push(Communication::RequestHeader.new('Content-Type', 'application/json'))
205
+ body = @marshaller.marshal(request_body)
206
+ else
207
+ # Set the content-type, even though there is no body, to prevent the httpClient from
208
+ # adding a content-type header after authentication has been generated.
209
+ request_headers.push(Communication::RequestHeader.new('Content-Type', 'text/plain'))
210
+ end
211
+
212
+ add_generic_headers('POST', uri, request_headers, context)
213
+
214
+ response_status_code, response_headers, response_body = nil
215
+ @connection.post(uri, request_headers, body) do |status_code, headers, content|
216
+ response_status_code = status_code
217
+ response_headers = headers
218
+ response_body = content.read.force_encoding('UTF-8')
219
+ end
220
+ process_response(response_body, response_status_code, response_headers, response_type, relative_path, context)
221
+ end
222
+
223
+ # Performs a POST request to the Worldline Acquiring platform and yields the response as the headers and body.
224
+ #
225
+ # @param relative_path [String] Path relative to the API endpoint
226
+ # @param request_headers [Array<Worldline::Acquiring::SDK::Communication::RequestHeader>, nil] Optional array of request headers
227
+ # @param request_parameters [Worldline::Acquiring::SDK::Communication::ParamRequest, nil] Optional request parameters
228
+ # @param request_body [Worldline::Acquiring::SDK::Domain::DataObject, Worldline::Acquiring::SDK::Communication::MultipartFormDataObject, Worldline::Acquiring::SDK::Communication::MultipartFormDataRequest, nil]
229
+ # The optional request body
230
+ # @param context [Worldline::Acquiring::SDK::CallContext, nil] Optional call context.
231
+ # @yield [Array<Worldline::Acquiring::SDK::Communication::ResponseHeader>, IO] The response headers and body.
232
+ # @raise [Worldline::Acquiring::SDK::Communication::ResponseException] if the request could not be fulfilled successfully.
233
+ # This occurs for example if the request is not authenticated correctly
234
+ # @raise [Worldline::Acquiring::SDK::Communication::NotFoundException] if the requested resource is not found
235
+ # @raise [Worldline::Acquiring::SDK::Communication::CommunicationException] if there is an error in communicating with the Worldline Acquiring platform.
236
+ # This occurs for example if a timeout occurs.
237
+ def post_with_binary_response(relative_path, request_headers, request_parameters, request_body, context)
238
+ request_parameter_list = request_parameters && request_parameters.to_request_parameters
239
+ uri = to_absolute_uri(relative_path, request_parameter_list)
240
+ request_headers = [] if request_headers.nil?
241
+
242
+ body = nil
243
+ if request_body.is_a? Communication::MultipartFormDataObject
244
+ request_headers.push(Communication::RequestHeader.new('Content-Type', request_body.content_type))
245
+ body = request_body
246
+ elsif request_body.is_a? Communication::MultipartFormDataRequest
247
+ multipart = request_body.to_multipart_form_data_object
248
+ request_headers.push(Communication::RequestHeader.new('Content-Type', multipart.content_type))
249
+ body = multipart
250
+ elsif !request_body.nil?
251
+ request_headers.push(Communication::RequestHeader.new('Content-Type', 'application/json'))
252
+ body = @marshaller.marshal(request_body)
253
+ else
254
+ # Set the content-type, even though there is no body, to prevent the httpClient from
255
+ # adding a content-type header after authentication has been generated.
256
+ request_headers.push(Communication::RequestHeader.new('Content-Type', 'text/plain'))
257
+ end
258
+ add_generic_headers('POST', uri, request_headers, context)
259
+
260
+ response_status_code, response_headers, response_body = nil
261
+ @connection.post(uri, request_headers, body) do |status_code, headers, content|
262
+ response_status_code = status_code
263
+ response_headers = headers
264
+ response_body = process_binary_response(status_code, content, headers, context) do |h, c|
265
+ yield h, c
266
+ end
267
+ end
268
+ throw_exception_if_necessary(response_body, response_status_code, response_headers, relative_path)
269
+ end
270
+
271
+ # Performs a PUT request to the Worldline Acquiring platform and returns the response as the given response type.
272
+ #
273
+ # @param relative_path [String] Path relative to the API endpoint
274
+ # @param request_headers [Array<Worldline::Acquiring::SDK::Communication::RequestHeader>, nil] Optional array of request headers
275
+ # @param request_parameters [Worldline::Acquiring::SDK::Communication::ParamRequest, nil] Optional request parameters
276
+ # @param request_body [Worldline::Acquiring::SDK::Domain::DataObject, Worldline::Acquiring::SDK::Communication::MultipartFormDataObject, Worldline::Acquiring::SDK::Communication::MultipartFormDataRequest, nil]
277
+ # The optional request body
278
+ # @param response_type [Type] The response type.
279
+ # @param context [Worldline::Acquiring::SDK::CallContext, nil] Optional call context.
280
+ # @return The response of the PUT request as the given response type
281
+ # @raise [Worldline::Acquiring::SDK::Communication::ResponseException] if the request could not be fulfilled successfully.
282
+ # This occurs for example if the request is not authenticated correctly
283
+ # @raise [Worldline::Acquiring::SDK::Communication::NotFoundException] if the requested resource is not found
284
+ # @raise [Worldline::Acquiring::SDK::Communication::CommunicationException] if there is an error in communicating with the Worldline Acquiring platform.
285
+ # This occurs for example if a timeout occurs.
286
+ def put(relative_path, request_headers, request_parameters, request_body, response_type, context)
287
+ request_parameter_list = request_parameters && request_parameters.to_request_parameters
288
+ uri = to_absolute_uri(relative_path, request_parameter_list)
289
+ request_headers = [] if request_headers.nil?
290
+
291
+ body = nil
292
+ if request_body.is_a? Communication::MultipartFormDataObject
293
+ request_headers.push(Communication::RequestHeader.new('Content-Type', request_body.content_type))
294
+ body = request_body
295
+ elsif request_body.is_a? Communication::MultipartFormDataRequest
296
+ multipart = request_body.to_multipart_form_data_object
297
+ request_headers.push(Communication::RequestHeader.new('Content-Type', multipart.content_type))
298
+ body = multipart
299
+ elsif !request_body.nil?
300
+ request_headers.push(Communication::RequestHeader.new('Content-Type', 'application/json'))
301
+ body = @marshaller.marshal(request_body)
302
+ else
303
+ # Set the content-type, even though there is no body, to prevent the httpClient from
304
+ # adding a content-type header after authentication has been generated.
305
+ request_headers.push(Communication::RequestHeader.new('Content-Type', 'text/plain'))
306
+ end
307
+ add_generic_headers('PUT', uri, request_headers, context)
308
+
309
+ response_status_code, response_headers, response_body = nil
310
+ @connection.put(uri, request_headers, body) do |status_code, headers, content|
311
+ response_status_code = status_code
312
+ response_headers = headers
313
+ response_body = content.read.force_encoding('UTF-8')
314
+ end
315
+ process_response(response_body, response_status_code, response_headers, response_type, relative_path, context)
316
+ end
317
+
318
+ # Performs a PUT request to the Worldline Acquiring platform and yields the response as the headers and body.
319
+ #
320
+ # @param relative_path [String] Path relative to the API endpoint
321
+ # @param request_headers [Array<Worldline::Acquiring::SDK::Communication::RequestHeader>, nil] Optional array of request headers
322
+ # @param request_parameters [Worldline::Acquiring::SDK::Communication::ParamRequest, nil] Optional request parameters
323
+ # @param request_body [Worldline::Acquiring::SDK::Domain::DataObject, Worldline::Acquiring::SDK::Communication::MultipartFormDataObject, Worldline::Acquiring::SDK::Communication::MultipartFormDataRequest, nil]
324
+ # The optional request body
325
+ # @param context [Worldline::Acquiring::SDK::CallContext, nil] Optional call context.
326
+ # @yield [Array<Worldline::Acquiring::SDK::Communication::ResponseHeader>, IO] The response headers and body.
327
+ # @raise [Worldline::Acquiring::SDK::Communication::ResponseException] if the request could not be fulfilled successfully.
328
+ # This occurs for example if the request is not authenticated correctly
329
+ # @raise [Worldline::Acquiring::SDK::Communication::NotFoundException] if the requested resource is not found
330
+ # @raise [Worldline::Acquiring::SDK::Communication::CommunicationException] if there is an error in communicating with the Worldline Acquiring platform.
331
+ # This occurs for example if a timeout occurs.
332
+ def put_with_binary_response(relative_path, request_headers, request_parameters, request_body, context)
333
+ request_parameter_list = request_parameters && request_parameters.to_request_parameters
334
+ uri = to_absolute_uri(relative_path, request_parameter_list)
335
+ request_headers = [] if request_headers.nil?
336
+
337
+ body = nil
338
+ if request_body.is_a? Communication::MultipartFormDataObject
339
+ request_headers.push(Communication::RequestHeader.new('Content-Type', request_body.content_type))
340
+ body = request_body
341
+ elsif request_body.is_a? Communication::MultipartFormDataRequest
342
+ multipart = request_body.to_multipart_form_data_object
343
+ request_headers.push(Communication::RequestHeader.new('Content-Type', multipart.content_type))
344
+ body = multipart
345
+ elsif !request_body.nil?
346
+ request_headers.push(Communication::RequestHeader.new('Content-Type', 'application/json'))
347
+ body = @marshaller.marshal(request_body)
348
+ else
349
+ # Set the content-type, even though there is no body, to prevent the httpClient from
350
+ # adding a content-type header after authentication has been generated.
351
+ request_headers.push(Communication::RequestHeader.new('Content-Type', 'text/plain'))
352
+ end
353
+ add_generic_headers('PUT', uri, request_headers, context)
354
+
355
+ response_status_code, response_headers, response_body = nil
356
+ @connection.put(uri, request_headers, body) do |status_code, headers, content|
357
+ response_status_code = status_code
358
+ response_headers = headers
359
+ response_body = process_binary_response(status_code, content, headers, context) do |h, c|
360
+ yield h, c
361
+ end
362
+ end
363
+ throw_exception_if_necessary(response_body, response_status_code, response_headers, relative_path)
364
+ end
365
+
366
+ # Closes any connections idle for more than _idle_time_ seconds.
367
+ # Will not have any effect if the connection is not a pooled connection (an instance of {Worldline::Acquiring::SDK::Communication::PooledConnection}).
368
+ def close_idle_connections(idle_time)
369
+ @connection.close_idle_connections(idle_time) if @connection.is_a? PooledConnection
370
+ end
371
+
372
+ # Closes any connections that have expired.
373
+ # Will not have any effect if the connection is not a pooled connection (an instance of {Worldline::Acquiring::SDK::Communication::PooledConnection}).
374
+ def close_expired_connections
375
+ @connection.close_expired_connections if @connection.is_a? PooledConnection
376
+ end
377
+
378
+ # Sets the current body obfuscator to use.
379
+ # @param body_obfuscator [Worldline::Acquiring::SDK::Logging::Obfuscation::BodyObfuscator]
380
+ def set_body_obfuscator(body_obfuscator)
381
+ @connection.set_body_obfuscator(body_obfuscator)
382
+ end
383
+
384
+ # Sets the current header obfuscator to use.
385
+ # @param header_obfuscator [Worldline::Acquiring::SDK::Logging::Obfuscation::HeaderObfuscator]
386
+ def set_header_obfuscator(header_obfuscator)
387
+ @connection.set_header_obfuscator(header_obfuscator)
388
+ end
389
+
390
+ # Enables logging outgoing requests and incoming responses by registering the _communicator_logger_.
391
+ # Note that only one logger can be registered at a time and calling _enable_logging_
392
+ # a second time will override the old logger instance with the new one.
393
+ #
394
+ # @param communicator_logger [Worldline::Acquiring::SDK::Logging::CommunicatorLogger] The communicator logger the requests and responses are logged to
395
+ def enable_logging(communicator_logger)
396
+ @connection.enable_logging(communicator_logger)
397
+ end
398
+
399
+ # Disables logging by unregistering any previous logger that might be registered.
400
+ def disable_logging
401
+ @connection.disable_logging
402
+ end
403
+
404
+ # Frees networking resources by closing the underlying network connections.
405
+ # After calling _close_, any use of the _get_, _delete_, _post_ and _put_ methods will not function
406
+ # and likely result in an error.
407
+ def close
408
+ @connection.close
409
+ end
410
+
411
+ attr_reader :marshaller
412
+
413
+ protected
414
+
415
+ # Constructs a full URL using the base URL and the given relative path and request_parameters.
416
+ # The returned URL is a *URI* object.
417
+ #
418
+ # @param relative_path [String] The relative path of the URL.
419
+ # @param request_parameters [Array<Worldline::Acquiring::SDK::Communication::RequestParam>] A list of request parameters that each have #name and #value
420
+ # which represent the parameter name and value respectively.
421
+ def to_absolute_uri(relative_path, request_parameters)
422
+ absolute_path = relative_path.start_with?('/') ? relative_path : '/' + relative_path
423
+ uri = URI::HTTP.new(@api_endpoint.scheme, nil, @api_endpoint.host,
424
+ @api_endpoint.port, nil, absolute_path, nil, nil, nil)
425
+ unless request_parameters.nil?
426
+ request_parameters.each do |nvp|
427
+ parameters = URI.decode_www_form(uri.query || '') << [nvp.name, nvp.value]
428
+ uri.query = URI.encode_www_form(parameters)
429
+ end
430
+ end
431
+ uri
432
+ end
433
+
434
+ # Adds several standard headers to the http headers.
435
+ # This method will add the 'Date' and 'Authorization' header
436
+ #
437
+ # @param http_method [String] 'GET', 'DELETE', 'POST' or 'PUT' depending on the HTTP method being used
438
+ # @param uri [URI::HTTP] The full URI to the Worldline Acquiring platform,
439
+ # including the relative path and request parameters.
440
+ # @param request_headers [Array<Worldline::Acquiring::SDK::Communication::RequestHeader>] List of request headers in which which new headers will be added
441
+ # @param context [Worldline::Acquiring::SDK::CallContext, nil] optional call context.
442
+ def add_generic_headers(http_method, uri, request_headers, context = nil)
443
+ request_headers.concat(@metadata_provider.metadata_headers)
444
+ request_headers.push(Communication::RequestHeader.new('Date', get_header_date_string))
445
+ request_headers.push(Communication::RequestHeader.new("Trace-Id", SecureRandom.uuid))
446
+ # no context specific headers at this time
447
+ authorization = @authenticator.get_authorization(http_method, uri, request_headers)
448
+ request_headers.push(Communication::RequestHeader.new('Authorization', authorization))
449
+ end
450
+
451
+ def get_header_date_string
452
+ Time.now.utc.strftime('%a, %d %b %Y %H:%M:%S GMT')
453
+ end
454
+
455
+ def process_response(body, status, headers, response_type, request_path, context)
456
+ update_context(headers, context) unless context.nil?
457
+
458
+ throw_exception_if_necessary(body, status, headers, request_path)
459
+ @marshaller.unmarshal(body, response_type)
460
+ end
461
+
462
+ def process_binary_response(status, body, headers, context)
463
+ update_context(response.headers, context) unless context.nil?
464
+
465
+ if status < 400
466
+ yield headers, body
467
+ ''
468
+ else
469
+ body.read.force_encoding('UTF-8')
470
+ end
471
+ end
472
+
473
+ def update_context(headers, context)
474
+ # no context specific headers at this time
475
+ end
476
+
477
+ def throw_exception_if_necessary(body, status_code, headers, request_path)
478
+ if status_code < 200 || status_code >= 300
479
+ if !body.nil? && !is_json(headers)
480
+ cause = Communication::ResponseException.new(status_code, headers, body)
481
+ if status_code == 404
482
+ raise Communication::NotFoundException.new(cause, 'The requested resource was not found; invalid path: ' +
483
+ request_path)
484
+ else
485
+ raise Communication::CommunicationException, cause
486
+ end
487
+ else
488
+ raise Communication::ResponseException.new(status_code, headers, body)
489
+ end
490
+ end
491
+ end
492
+
493
+ private
494
+
495
+ def is_json(headers)
496
+ content_type = Communication::ResponseHeader.get_header_value(headers, 'Content-Type')
497
+ if content_type.nil? || 'application/json'.casecmp(content_type) == 0 || 'application/problem+json'.casecmp(content_type) == 0
498
+ return true
499
+ end
500
+ content_type = content_type.downcase
501
+ content_type.start_with?('application/json') || content_type.start_with?('application/problem+json')
502
+ end
503
+ end
504
+ end
505
+ end
506
+ end