workato-connector-sdk 1.0.3 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +1 -0
- data/lib/workato/cli/exec_command.rb +31 -8
- data/lib/workato/cli/multi_auth_selected_fallback.rb +33 -0
- data/lib/workato/cli/oauth2_command.rb +50 -12
- data/lib/workato/connector/sdk/connection.rb +84 -14
- data/lib/workato/connector/sdk/connector.rb +6 -4
- data/lib/workato/connector/sdk/dsl/aws.rb +5 -2
- data/lib/workato/connector/sdk/dsl/call.rb +5 -2
- data/lib/workato/connector/sdk/dsl/csv.rb +125 -0
- data/lib/workato/connector/sdk/dsl/execution_context.rb +44 -0
- data/lib/workato/connector/sdk/dsl/workato_code_lib.rb +8 -1
- data/lib/workato/connector/sdk/dsl.rb +1 -0
- data/lib/workato/connector/sdk/errors.rb +69 -1
- data/lib/workato/connector/sdk/lookup_tables.rb +3 -1
- data/lib/workato/connector/sdk/object_definitions.rb +16 -10
- data/lib/workato/connector/sdk/operation.rb +24 -8
- data/lib/workato/connector/sdk/request.rb +136 -58
- data/lib/workato/connector/sdk/schema.rb +5 -3
- data/lib/workato/connector/sdk/settings.rb +4 -2
- data/lib/workato/connector/sdk/trigger.rb +42 -19
- data/lib/workato/connector/sdk/version.rb +1 -1
- data/lib/workato/connector/sdk.rb +3 -2
- data/lib/workato/extension/case_sensitive_headers.rb +0 -25
- data/lib/workato/extension/content_encoding_decoder.rb +67 -0
- data/lib/workato/extension/currency.rb +1 -1
- data/lib/workato/extension/extra_chain_cert.rb +0 -14
- data/lib/workato/extension/hash_with_indifferent_access.rb +19 -0
- data/lib/workato/extension/phone.rb +1 -1
- data/lib/workato/extension/string.rb +6 -2
- data/lib/workato/utilities/encoding.rb +57 -0
- data/lib/workato/{connector/sdk → utilities}/xml.rb +4 -4
- metadata +48 -22
@@ -0,0 +1,44 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'securerandom'
|
5
|
+
|
6
|
+
module Workato
|
7
|
+
module Connector
|
8
|
+
module Sdk
|
9
|
+
module Dsl
|
10
|
+
module ExecutionContext
|
11
|
+
extend T::Sig
|
12
|
+
extend T::Helpers
|
13
|
+
extend ActiveSupport::Concern
|
14
|
+
|
15
|
+
included do
|
16
|
+
T.bind(self, Class)
|
17
|
+
|
18
|
+
# encrypted safe recipe_id
|
19
|
+
class_attribute :recipe_id, instance_predicate: false, default: SecureRandom.hex(32)
|
20
|
+
end
|
21
|
+
|
22
|
+
sig { returns(T::Hash[Symbol, T.untyped]) }
|
23
|
+
def execution_context
|
24
|
+
@execution_context ||= {
|
25
|
+
recipe_id: recipe_id
|
26
|
+
}.compact
|
27
|
+
end
|
28
|
+
|
29
|
+
# mock unencrypted recipe_id for testing only
|
30
|
+
def recipe_id!
|
31
|
+
recipe_id.reverse
|
32
|
+
end
|
33
|
+
|
34
|
+
module ClassMethods
|
35
|
+
# mock unencrypted recipe_id for testing only
|
36
|
+
def recipe_id!
|
37
|
+
T.unsafe(self).recipe_id.reverse
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -2,6 +2,9 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require 'jwt'
|
5
|
+
require_relative './csv'
|
6
|
+
|
7
|
+
using Workato::Extension::HashWithIndifferentAccess
|
5
8
|
|
6
9
|
module Workato
|
7
10
|
module Connector
|
@@ -74,7 +77,7 @@ module Workato
|
|
74
77
|
raise "A RSA key of size #{JWT_RSA_KEY_MIN_LENGTH} bits or larger MUST be used with JWT."
|
75
78
|
end
|
76
79
|
|
77
|
-
header_fields =
|
80
|
+
header_fields = HashWithIndifferentAccess.wrap(header_fields).except(:typ, :alg)
|
78
81
|
::JWT.encode(payload, rsa_private, algorithm, header_fields)
|
79
82
|
end
|
80
83
|
|
@@ -152,6 +155,10 @@ module Workato
|
|
152
155
|
def pbkdf2_hmac_sha1(string, salt, iterations = 1000, key_len = 16)
|
153
156
|
Extension::Binary.new(::OpenSSL::PKCS5.pbkdf2_hmac_sha1(string, salt, iterations, key_len))
|
154
157
|
end
|
158
|
+
|
159
|
+
def csv
|
160
|
+
Csv
|
161
|
+
end
|
155
162
|
end
|
156
163
|
end
|
157
164
|
end
|
@@ -6,12 +6,62 @@ module Workato
|
|
6
6
|
module Sdk
|
7
7
|
InvalidDefinitionError = Class.new(StandardError)
|
8
8
|
|
9
|
-
|
9
|
+
class UnexpectedMethodDefinitionError < InvalidDefinitionError
|
10
|
+
attr_reader :name
|
11
|
+
attr_reader :definition
|
12
|
+
|
13
|
+
def initialize(name, definition)
|
14
|
+
super("Expected lambda for method '#{name}' definition, got: #{definition.class.name}")
|
15
|
+
@name = name
|
16
|
+
@definition = definition
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class UndefinedMethodError < InvalidDefinitionError
|
21
|
+
attr_reader :name
|
22
|
+
|
23
|
+
def initialize(name)
|
24
|
+
super("Method '#{name}' does not exists")
|
25
|
+
@name = name
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
InvalidSchemaError = Class.new(InvalidDefinitionError)
|
10
30
|
|
11
31
|
CustomRequestError = Class.new(StandardError)
|
12
32
|
|
33
|
+
InvalidMultiAuthDefinition = Class.new(InvalidDefinitionError)
|
34
|
+
|
35
|
+
class UnresolvedMultiAuthOptionError < InvalidMultiAuthDefinition
|
36
|
+
attr_reader :name
|
37
|
+
|
38
|
+
def initialize(name)
|
39
|
+
super("Cannot find multi-auth definition for '#{name}'")
|
40
|
+
@name = name
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
13
44
|
RuntimeError = Class.new(StandardError)
|
14
45
|
|
46
|
+
class UnresolvedObjectDefinitionError < StandardError
|
47
|
+
attr_reader :name
|
48
|
+
|
49
|
+
def initialize(name)
|
50
|
+
super("Cannot find object definition for '#{name}'")
|
51
|
+
@name = name
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class CircleReferenceObjectDefinitionError < StandardError
|
56
|
+
attr_reader :name
|
57
|
+
|
58
|
+
def initialize(name, backtrace = [])
|
59
|
+
super("Infinite recursion occurred in object definition for '#{name}'")
|
60
|
+
set_backtrace(backtrace)
|
61
|
+
@name = name
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
15
65
|
class RequestError < StandardError
|
16
66
|
attr_reader :method
|
17
67
|
attr_reader :code
|
@@ -41,6 +91,24 @@ module Workato
|
|
41
91
|
super(message)
|
42
92
|
end
|
43
93
|
end
|
94
|
+
|
95
|
+
RequestTLSCertificateFormatError = Class.new(StandardError)
|
96
|
+
|
97
|
+
RequestPayloadFormatError = Class.new(StandardError)
|
98
|
+
|
99
|
+
JSONRequestFormatError = Class.new(RequestPayloadFormatError)
|
100
|
+
|
101
|
+
JSONResponseFormatError = Class.new(RequestPayloadFormatError)
|
102
|
+
|
103
|
+
XMLRequestFormatError = Class.new(RequestPayloadFormatError)
|
104
|
+
|
105
|
+
XMLResponseFormatError = Class.new(RequestPayloadFormatError)
|
106
|
+
|
107
|
+
WWWFormURLEncodedRequestFormatError = Class.new(RequestPayloadFormatError)
|
108
|
+
|
109
|
+
MultipartFormRequestFormatError = Class.new(RequestPayloadFormatError)
|
110
|
+
|
111
|
+
RAWResponseFormatError = Class.new(RequestPayloadFormatError)
|
44
112
|
end
|
45
113
|
end
|
46
114
|
end
|
@@ -4,6 +4,8 @@
|
|
4
4
|
require 'csv'
|
5
5
|
require 'singleton'
|
6
6
|
|
7
|
+
using Workato::Extension::HashWithIndifferentAccess
|
8
|
+
|
7
9
|
module Workato
|
8
10
|
module Connector
|
9
11
|
module Sdk
|
@@ -40,7 +42,7 @@ module Workato
|
|
40
42
|
@table_by_id ||= {}
|
41
43
|
@table_by_name ||= {}
|
42
44
|
data.each do |name, table|
|
43
|
-
table = table
|
45
|
+
table = HashWithIndifferentAccess.wrap(table)
|
44
46
|
rows = table['rows'].freeze
|
45
47
|
@table_by_id[table['id'].to_i] = rows
|
46
48
|
@table_by_name[name] = rows
|
@@ -18,16 +18,22 @@ module Workato
|
|
18
18
|
|
19
19
|
def lazy(settings = nil, config_fields = {})
|
20
20
|
DupHashWithIndifferentAccess.new do |object_definitions, name|
|
21
|
-
fields_proc = object_definitions_source
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
21
|
+
fields_proc = object_definitions_source.dig(name, :fields)
|
22
|
+
raise Workato::Connector::Sdk::UnresolvedObjectDefinitionError, name unless fields_proc
|
23
|
+
|
24
|
+
begin
|
25
|
+
object_definitions[name] = Action.new(
|
26
|
+
action: {
|
27
|
+
execute: lambda do |connection, input|
|
28
|
+
instance_exec(connection, input, object_definitions, &fields_proc)
|
29
|
+
end
|
30
|
+
},
|
31
|
+
methods: methods_source,
|
32
|
+
connection: connection
|
33
|
+
).execute(settings, config_fields)
|
34
|
+
rescue SystemStackError => e
|
35
|
+
raise Workato::Connector::Sdk::CircleReferenceObjectDefinitionError.new(name, e.backtrace)
|
36
|
+
end
|
31
37
|
end
|
32
38
|
end
|
33
39
|
|
@@ -5,6 +5,8 @@ require_relative './dsl'
|
|
5
5
|
require_relative './block_invocation_refinements'
|
6
6
|
require_relative './schema'
|
7
7
|
|
8
|
+
using Workato::Extension::HashWithIndifferentAccess
|
9
|
+
|
8
10
|
module Workato
|
9
11
|
module Connector
|
10
12
|
module Sdk
|
@@ -45,6 +47,7 @@ module Workato
|
|
45
47
|
include Dsl::HTTP
|
46
48
|
include Dsl::Call
|
47
49
|
include Dsl::Error
|
50
|
+
include Dsl::ExecutionContext
|
48
51
|
|
49
52
|
using BlockInvocationRefinements
|
50
53
|
|
@@ -57,8 +60,8 @@ module Workato
|
|
57
60
|
).void
|
58
61
|
end
|
59
62
|
def initialize(operation: {}, methods: {}, connection: Connection.new, object_definitions: nil)
|
60
|
-
@operation = T.let(operation
|
61
|
-
@_methods = T.let(methods
|
63
|
+
@operation = T.let(HashWithIndifferentAccess.wrap(operation), HashWithIndifferentAccess)
|
64
|
+
@_methods = T.let(HashWithIndifferentAccess.wrap(methods), HashWithIndifferentAccess)
|
62
65
|
@connection = T.let(connection, Connection)
|
63
66
|
@object_definitions = T.let(object_definitions, T.nilable(ObjectDefinitions))
|
64
67
|
end
|
@@ -80,13 +83,14 @@ module Workato
|
|
80
83
|
connection.merge_settings!(settings) if settings
|
81
84
|
request_or_result = T.unsafe(self).instance_exec(
|
82
85
|
connection.settings,
|
83
|
-
input
|
84
|
-
Array.wrap(extended_input_schema).map(
|
85
|
-
Array.wrap(extended_output_schema).map(
|
86
|
-
continue
|
86
|
+
HashWithIndifferentAccess.wrap(input),
|
87
|
+
Array.wrap(extended_input_schema).map { |i| HashWithIndifferentAccess.wrap(i) },
|
88
|
+
Array.wrap(extended_output_schema).map { |i| HashWithIndifferentAccess.wrap(i) },
|
89
|
+
HashWithIndifferentAccess.wrap(continue),
|
87
90
|
&block
|
88
91
|
)
|
89
|
-
resolve_request(request_or_result)
|
92
|
+
result = resolve_request(request_or_result)
|
93
|
+
try_convert_to_hash_with_indifferent_access(result)
|
90
94
|
end
|
91
95
|
|
92
96
|
sig do
|
@@ -225,7 +229,7 @@ module Workato
|
|
225
229
|
end
|
226
230
|
end
|
227
231
|
when ::Hash
|
228
|
-
request_or_result.inject(request_or_result
|
232
|
+
request_or_result.inject(request_or_result) do |acc, (key, value)|
|
229
233
|
response_value = resolve_request(value)
|
230
234
|
if response_value.equal?(value)
|
231
235
|
acc
|
@@ -238,6 +242,18 @@ module Workato
|
|
238
242
|
end
|
239
243
|
end
|
240
244
|
|
245
|
+
sig { params(value: T.untyped).returns(T.untyped) }
|
246
|
+
def try_convert_to_hash_with_indifferent_access(value)
|
247
|
+
case value
|
248
|
+
when ::Hash
|
249
|
+
HashWithIndifferentAccess.wrap(value)
|
250
|
+
when ::Array
|
251
|
+
value.map! { |i| try_convert_to_hash_with_indifferent_access(i) }
|
252
|
+
else
|
253
|
+
value
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
241
257
|
sig { returns(ObjectDefinitions) }
|
242
258
|
def object_definitions
|
243
259
|
T.must(@object_definitions)
|
@@ -8,8 +8,12 @@ require 'gyoku'
|
|
8
8
|
require 'net/http'
|
9
9
|
require 'net/http/digest_auth'
|
10
10
|
|
11
|
+
require 'workato/utilities/encoding'
|
12
|
+
require 'workato/utilities/xml'
|
11
13
|
require_relative './block_invocation_refinements'
|
12
14
|
|
15
|
+
using Workato::Extension::HashWithIndifferentAccess
|
16
|
+
|
13
17
|
module Workato
|
14
18
|
module Connector
|
15
19
|
module Sdk
|
@@ -27,10 +31,10 @@ module Workato
|
|
27
31
|
@action = action
|
28
32
|
@headers = {}
|
29
33
|
@case_sensitive_headers = {}
|
30
|
-
@params = {}.with_indifferent_access
|
31
34
|
@render_request = ->(payload) { payload }
|
32
35
|
@parse_response = ->(payload) { payload }
|
33
36
|
@after_response = ->(_response_code, parsed_response, _response_headers) { parsed_response }
|
37
|
+
@callstack_before_request = Array.wrap(Kernel.caller)
|
34
38
|
end
|
35
39
|
|
36
40
|
def method_missing(*args, &block)
|
@@ -38,36 +42,24 @@ module Workato
|
|
38
42
|
end
|
39
43
|
|
40
44
|
def execute!
|
41
|
-
__getobj__ || __setobj__(
|
42
|
-
authorized do
|
43
|
-
begin
|
44
|
-
request = build_request
|
45
|
-
response = execute(request)
|
46
|
-
rescue RestClient::Unauthorized => e
|
47
|
-
Kernel.raise e unless @digest_auth
|
48
|
-
|
49
|
-
@digest_auth = false
|
50
|
-
headers('Authorization' => Net::HTTP::DigestAuth.new.auth_header(
|
51
|
-
URI.parse(build_url),
|
52
|
-
e.response.headers[:www_authenticate],
|
53
|
-
method.to_s.upcase
|
54
|
-
))
|
55
|
-
request = build_request
|
56
|
-
response = execute(request)
|
57
|
-
end
|
58
|
-
detect_error!(response.body)
|
59
|
-
parsed_response = @parse_response.call(response)
|
60
|
-
detect_error!(parsed_response)
|
61
|
-
within_action_context(response.code, parsed_response, response.headers, &@after_response)
|
62
|
-
end
|
63
|
-
)
|
45
|
+
__getobj__ || __setobj__(response)
|
64
46
|
rescue RestClient::Exception => e
|
65
47
|
if after_error_response_matches?(e)
|
66
48
|
return apply_after_error_response(e)
|
67
49
|
end
|
68
50
|
|
69
|
-
Kernel.raise RequestError.new(
|
70
|
-
|
51
|
+
Kernel.raise RequestError.new(
|
52
|
+
response: e.response,
|
53
|
+
message: e.message,
|
54
|
+
method: current_verb,
|
55
|
+
code: e.http_code
|
56
|
+
)
|
57
|
+
rescue StandardError => e
|
58
|
+
error_backtrace = Array.wrap(e.backtrace)
|
59
|
+
first_call_after_request_idx = error_backtrace.rindex { |s| s.start_with?(__FILE__) }
|
60
|
+
error_backtrace_after_request = error_backtrace[0..first_call_after_request_idx]
|
61
|
+
e.set_backtrace(error_backtrace_after_request + @callstack_before_request)
|
62
|
+
Kernel.raise e
|
71
63
|
end
|
72
64
|
|
73
65
|
def headers(headers)
|
@@ -81,7 +73,12 @@ module Workato
|
|
81
73
|
end
|
82
74
|
|
83
75
|
def params(params)
|
84
|
-
|
76
|
+
if params.is_a?(Hash)
|
77
|
+
@params ||= HashWithIndifferentAccess.new
|
78
|
+
@params.merge!(params)
|
79
|
+
else
|
80
|
+
@params = params
|
81
|
+
end
|
85
82
|
self
|
86
83
|
end
|
87
84
|
|
@@ -142,13 +139,17 @@ module Workato
|
|
142
139
|
|
143
140
|
def request_format_json
|
144
141
|
@content_type_header = :json
|
145
|
-
@render_request =
|
142
|
+
@render_request = lambda_with_error_wrap(JSONRequestFormatError) do |payload|
|
143
|
+
ActiveSupport::JSON.encode(payload) if payload
|
144
|
+
end
|
146
145
|
self
|
147
146
|
end
|
148
147
|
|
149
148
|
def response_format_json
|
150
149
|
@accept_header = :json
|
151
|
-
@parse_response =
|
150
|
+
@parse_response = lambda_with_error_wrap(JSONResponseFormatError) do |payload|
|
151
|
+
ActiveSupport::JSON.decode(payload.presence || '{}')
|
152
|
+
end
|
152
153
|
self
|
153
154
|
end
|
154
155
|
|
@@ -158,17 +159,19 @@ module Workato
|
|
158
159
|
|
159
160
|
def request_format_xml(root_element_name, namespaces = {})
|
160
161
|
@content_type_header = :xml
|
161
|
-
@render_request =
|
162
|
+
@render_request = lambda_with_error_wrap(XMLRequestFormatError) do |payload|
|
162
163
|
next unless payload
|
163
164
|
|
164
165
|
Gyoku.xml({ root_element_name => payload.merge(namespaces).deep_symbolize_keys }, key_converter: :none)
|
165
|
-
|
166
|
+
end
|
166
167
|
self
|
167
168
|
end
|
168
169
|
|
169
170
|
def response_format_xml(strip_response_namespaces: false)
|
170
171
|
@accept_header = :xml
|
171
|
-
@parse_response =
|
172
|
+
@parse_response = lambda_with_error_wrap(XMLResponseFormatError) do |payload|
|
173
|
+
Workato::Utilities::Xml.parse_xml_to_hash(payload, strip_namespaces: strip_response_namespaces)
|
174
|
+
end
|
172
175
|
self
|
173
176
|
end
|
174
177
|
|
@@ -179,7 +182,7 @@ module Workato
|
|
179
182
|
end
|
180
183
|
|
181
184
|
def response_format_raw
|
182
|
-
@parse_response =
|
185
|
+
@parse_response = lambda_with_error_wrap(RAWResponseFormatError) do |payload|
|
183
186
|
payload.body.force_encoding(::Encoding::BINARY)
|
184
187
|
payload.body.valid_encoding? ? payload.body : payload.body.force_encoding(::Encoding::BINARY)
|
185
188
|
end
|
@@ -189,7 +192,7 @@ module Workato
|
|
189
192
|
def request_format_multipart_form
|
190
193
|
@content_type_header = nil
|
191
194
|
|
192
|
-
@render_request =
|
195
|
+
@render_request = lambda_with_error_wrap(MultipartFormRequestFormatError) do |payload|
|
193
196
|
payload&.each_with_object({}) do |(name, (value, content_type, original_filename)), rendered|
|
194
197
|
rendered[name] = if content_type.present?
|
195
198
|
Part.new(name, content_type, original_filename || ::File.basename(name), value.to_s)
|
@@ -204,7 +207,7 @@ module Workato
|
|
204
207
|
|
205
208
|
def request_format_www_form_urlencoded
|
206
209
|
@content_type_header = 'application/x-www-form-urlencoded'
|
207
|
-
@render_request =
|
210
|
+
@render_request = lambda_with_error_wrap(WWWFormURLEncodedRequestFormatError, &:to_param)
|
208
211
|
self
|
209
212
|
end
|
210
213
|
|
@@ -228,6 +231,8 @@ module Workato
|
|
228
231
|
OpenSSL::X509::Certificate.new(intermediate)
|
229
232
|
end
|
230
233
|
self
|
234
|
+
rescue OpenSSL::OpenSSLError => e
|
235
|
+
Kernel.raise(RequestTLSCertificateFormatError, e)
|
231
236
|
end
|
232
237
|
|
233
238
|
def tls_server_certs(certificates:, strict: true)
|
@@ -237,17 +242,47 @@ module Workato
|
|
237
242
|
@ssl_cert_store.add_cert(OpenSSL::X509::Certificate.new(certificate))
|
238
243
|
end
|
239
244
|
self
|
245
|
+
rescue OpenSSL::OpenSSLError => e
|
246
|
+
Kernel.raise(RequestTLSCertificateFormatError, e)
|
240
247
|
end
|
241
248
|
|
242
249
|
def puts(*args)
|
243
250
|
::Kernel.puts(*args)
|
244
251
|
end
|
245
252
|
|
253
|
+
def try(*args, &block)
|
254
|
+
execute!.try(*args, &block)
|
255
|
+
end
|
256
|
+
|
246
257
|
private
|
247
258
|
|
248
259
|
attr_reader :method
|
249
260
|
|
250
|
-
def
|
261
|
+
def response
|
262
|
+
authorized do
|
263
|
+
begin
|
264
|
+
request = RestClientRequest.new(rest_request_params)
|
265
|
+
response = execute_request(request)
|
266
|
+
rescue RestClient::Unauthorized => e
|
267
|
+
Kernel.raise e unless @digest_auth
|
268
|
+
|
269
|
+
@digest_auth = false
|
270
|
+
headers('Authorization' => Net::HTTP::DigestAuth.new.auth_header(
|
271
|
+
URI.parse(build_url),
|
272
|
+
e.response.headers[:www_authenticate],
|
273
|
+
method.to_s.upcase
|
274
|
+
))
|
275
|
+
request = RestClientRequest.new(rest_request_params)
|
276
|
+
response = execute_request(request)
|
277
|
+
end
|
278
|
+
detect_error!(response.body)
|
279
|
+
parsed_response = @parse_response.call(response)
|
280
|
+
detect_error!(parsed_response)
|
281
|
+
apply_after_response(response.code, parsed_response, response.headers)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
def execute_request(request)
|
251
286
|
if @follow_redirection.nil?
|
252
287
|
request.execute
|
253
288
|
else
|
@@ -266,25 +301,22 @@ module Workato
|
|
266
301
|
end
|
267
302
|
end
|
268
303
|
|
269
|
-
def
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
304
|
+
def rest_request_params
|
305
|
+
{
|
306
|
+
method: method,
|
307
|
+
url: build_url,
|
308
|
+
headers: build_headers,
|
309
|
+
payload: @render_request.call(@payload),
|
310
|
+
case_sensitive_headers: @case_sensitive_headers.transform_keys(&:to_s)
|
311
|
+
}.tap do |request_hash|
|
312
|
+
if @ssl_client_cert.present? && @ssl_client_key.present?
|
313
|
+
request_hash[:ssl_client_cert] = @ssl_client_cert
|
314
|
+
request_hash[:ssl_client_key] = @ssl_client_key
|
315
|
+
if @ssl_client_intermediate_certs.present?
|
316
|
+
request_hash[:ssl_extra_chain_cert] = @ssl_client_intermediate_certs
|
280
317
|
end
|
281
|
-
request_hash[:ssl_cert_store] = @ssl_cert_store if @ssl_cert_store
|
282
|
-
end
|
283
|
-
).tap do |request|
|
284
|
-
request.case_sensitive_headers = @case_sensitive_headers.transform_keys(&:to_s)
|
285
|
-
if @ssl_client_intermediate_certs.present? && @ssl_client_cert.present? && @ssl_client_key.present?
|
286
|
-
request.extra_chain_cert = @ssl_client_intermediate_certs
|
287
318
|
end
|
319
|
+
request_hash[:ssl_cert_store] = @ssl_cert_store if @ssl_cert_store
|
288
320
|
end
|
289
321
|
end
|
290
322
|
|
@@ -295,14 +327,14 @@ module Workato
|
|
295
327
|
URI.parse(@uri)
|
296
328
|
end
|
297
329
|
|
298
|
-
return uri.to_s unless @params
|
330
|
+
return uri.to_s unless @params || @user || @password
|
299
331
|
|
300
332
|
unless @digest_auth
|
301
333
|
uri.user = URI.encode_www_form_component(@user) if @user
|
302
334
|
uri.password = URI.encode_www_form_component(@password) if @password
|
303
335
|
end
|
304
336
|
|
305
|
-
return uri.to_s unless @params
|
337
|
+
return uri.to_s unless @params
|
306
338
|
|
307
339
|
query = uri.query.to_s.split('&').select(&:present?).join('&').presence
|
308
340
|
params = @params.to_param.presence
|
@@ -354,12 +386,19 @@ module Workato
|
|
354
386
|
within_action_context(
|
355
387
|
exception.http_code,
|
356
388
|
exception.http_body,
|
357
|
-
exception.http_headers
|
389
|
+
HashWithIndifferentAccess.wrap(exception.http_headers),
|
358
390
|
exception.message,
|
359
391
|
&@after_error_response
|
360
392
|
)
|
361
393
|
end
|
362
394
|
|
395
|
+
def apply_after_response(code, parsed_response, headers)
|
396
|
+
encoded_headers = (headers || {}).each_with_object(HashWithIndifferentAccess.new) do |(k, v), h|
|
397
|
+
h[k] = Workato::Utilities::Encoding.force_best_encoding!(v.to_s)
|
398
|
+
end
|
399
|
+
within_action_context(code, parsed_response, encoded_headers, &@after_response)
|
400
|
+
end
|
401
|
+
|
363
402
|
def within_action_context(*args, &block)
|
364
403
|
(@action || self).instance_exec(*args, &block)
|
365
404
|
end
|
@@ -378,13 +417,13 @@ module Workato
|
|
378
417
|
first = true
|
379
418
|
begin
|
380
419
|
settings = connection.settings
|
381
|
-
if
|
420
|
+
if connection.authorization.oauth2?
|
382
421
|
instance_exec(settings, settings[:access_token], @auth_type, &apply)
|
383
422
|
else
|
384
423
|
instance_exec(settings, @auth_type, &apply)
|
385
424
|
end
|
386
425
|
yield
|
387
|
-
rescue
|
426
|
+
rescue RestClient::Exception, CustomRequestError => e
|
388
427
|
Kernel.raise e unless first
|
389
428
|
Kernel.raise e unless refresh_authorization!(e.try(:http_code), e.try(:http_body), e.message)
|
390
429
|
|
@@ -413,6 +452,16 @@ module Workato
|
|
413
452
|
T.must(@connection)
|
414
453
|
end
|
415
454
|
|
455
|
+
def lambda_with_error_wrap(error_type, &block)
|
456
|
+
Kernel.lambda do |payload|
|
457
|
+
begin
|
458
|
+
block.call(payload)
|
459
|
+
rescue StandardError => e
|
460
|
+
Kernel.raise error_type.new(e)
|
461
|
+
end
|
462
|
+
end
|
463
|
+
end
|
464
|
+
|
416
465
|
class Part < StringIO
|
417
466
|
def initialize(path, content_type, original_filename, *args)
|
418
467
|
super(*args)
|
@@ -425,6 +474,35 @@ module Workato
|
|
425
474
|
attr_reader :content_type
|
426
475
|
attr_reader :original_filename
|
427
476
|
end
|
477
|
+
|
478
|
+
class RestClientRequest < ::RestClient::Request
|
479
|
+
def initialize(args)
|
480
|
+
super
|
481
|
+
@ssl_opts[:extra_chain_cert] = args[:ssl_extra_chain_cert] if args.key?(:ssl_extra_chain_cert)
|
482
|
+
@case_sensitive_headers = args[:case_sensitive_headers]
|
483
|
+
@before_execution_proc = proc do |net_http_request, _args|
|
484
|
+
net_http_request.case_sensitive_headers = args[:case_sensitive_headers]
|
485
|
+
end
|
486
|
+
end
|
487
|
+
|
488
|
+
def ssl_extra_chain_cert
|
489
|
+
@ssl_opts[:extra_chain_cert]
|
490
|
+
end
|
491
|
+
|
492
|
+
def processed_headers
|
493
|
+
return @processed_headers if @case_sensitive_headers.blank?
|
494
|
+
return @case_sensitive_headers if @processed_headers.blank?
|
495
|
+
|
496
|
+
@processed_headers.merge(@case_sensitive_headers)
|
497
|
+
end
|
498
|
+
|
499
|
+
def net_http_object(hostname, port)
|
500
|
+
net = super(hostname, port)
|
501
|
+
net.extra_chain_cert = ssl_extra_chain_cert if ssl_extra_chain_cert
|
502
|
+
net
|
503
|
+
end
|
504
|
+
end
|
505
|
+
private_constant :RestClientRequest
|
428
506
|
end
|
429
507
|
end
|
430
508
|
end
|
@@ -1,20 +1,22 @@
|
|
1
1
|
# typed: false
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
using Workato::Extension::HashWithIndifferentAccess
|
5
|
+
|
4
6
|
module Workato
|
5
7
|
module Connector
|
6
8
|
module Sdk
|
7
9
|
class Schema < SimpleDelegator
|
8
10
|
def initialize(schema: [])
|
9
|
-
super(Fields.new(::Array.wrap(schema).map(
|
11
|
+
super(Fields.new(::Array.wrap(schema).map { |i| HashWithIndifferentAccess.wrap(i) }))
|
10
12
|
end
|
11
13
|
|
12
14
|
def trim(input)
|
13
|
-
input.
|
15
|
+
HashWithIndifferentAccess.wrap(input).keep_if { |property_name| includes_property?(property_name) }
|
14
16
|
end
|
15
17
|
|
16
18
|
def apply(input, enforce_required:, &block)
|
17
|
-
input.
|
19
|
+
HashWithIndifferentAccess.wrap(input).tap do |input_with_indifferent_access|
|
18
20
|
apply_to_hash(self, input_with_indifferent_access, enforce_required: enforce_required, &block)
|
19
21
|
end
|
20
22
|
end
|