ms_rest2 0.7.6
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +52 -0
- data/LICENSE.txt +21 -0
- data/README.md +67 -0
- data/ca-cert.pem +3865 -0
- data/lib/ms_rest/credentials/basic_authentication_credentials.rb +62 -0
- data/lib/ms_rest/credentials/service_client_credentials.rb +22 -0
- data/lib/ms_rest/credentials/string_token_provider.rb +41 -0
- data/lib/ms_rest/credentials/token_credentials.rb +61 -0
- data/lib/ms_rest/credentials/token_provider.rb +19 -0
- data/lib/ms_rest/deserialization_error.rb +43 -0
- data/lib/ms_rest/http_operation_error.rb +72 -0
- data/lib/ms_rest/http_operation_request.rb +135 -0
- data/lib/ms_rest/http_operation_response.rb +37 -0
- data/lib/ms_rest/jsonable.rb +39 -0
- data/lib/ms_rest/rest_error.rb +11 -0
- data/lib/ms_rest/retry_policy_middleware.rb +44 -0
- data/lib/ms_rest/serialization.rb +483 -0
- data/lib/ms_rest/service_client.rb +115 -0
- data/lib/ms_rest/validation_error.rb +11 -0
- data/lib/ms_rest/version.rb +7 -0
- data/lib/ms_rest.rb +29 -0
- metadata +158 -0
@@ -0,0 +1,483 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for license information.
|
4
|
+
|
5
|
+
module MsRest
|
6
|
+
# Base module for Ruby serialization and deserialization.
|
7
|
+
#
|
8
|
+
# Provides methods to serialize Ruby object into Ruby Hash and
|
9
|
+
# to deserialize Ruby Hash into Ruby object.
|
10
|
+
module Serialization
|
11
|
+
#
|
12
|
+
# Deserialize the response from the server using the mapper.
|
13
|
+
#
|
14
|
+
# @param mapper [Hash] Ruby Hash object to represent expected structure of the response_body.
|
15
|
+
# @param response_body [Hash] Ruby Hash object to deserialize.
|
16
|
+
# @param object_name [String] Name of the deserialized object.
|
17
|
+
#
|
18
|
+
def deserialize(mapper, response_body)
|
19
|
+
build_serializer.deserialize(mapper, response_body)
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Serialize the Ruby object into Ruby Hash to send it to the server using the mapper.
|
24
|
+
#
|
25
|
+
# @param mapper [Hash] Ruby Hash object to represent expected structure of the object.
|
26
|
+
# @param object [Object] Ruby object to serialize.
|
27
|
+
# @param object_name [String] Name of the serialized object.
|
28
|
+
#
|
29
|
+
def serialize(mapper, object)
|
30
|
+
build_serializer.serialize(mapper, object)
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
#
|
36
|
+
# Builds serializer
|
37
|
+
#
|
38
|
+
def build_serializer
|
39
|
+
Serialization.new(self)
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# Class to handle serialization & deserialization.
|
44
|
+
#
|
45
|
+
class Serialization
|
46
|
+
def initialize(context)
|
47
|
+
@context = context
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Deserialize the response from the server using the mapper.
|
52
|
+
#
|
53
|
+
# @param mapper [Hash] Ruby Hash object to represent expected structure of the response_body.
|
54
|
+
# @param response_body [Hash] Ruby Hash object to deserialize.
|
55
|
+
# @param object_name [String] Name of the deserialized object.
|
56
|
+
#
|
57
|
+
def deserialize(mapper, response_body)
|
58
|
+
return response_body if response_body.nil?
|
59
|
+
|
60
|
+
object_name = mapper[:serialized_name]
|
61
|
+
mapper_type = mapper[:type][:name]
|
62
|
+
|
63
|
+
if !mapper_type.match(/^(Number|Double|ByteArray|Boolean|Date|DateTime|DateTimeRfc1123|TimeSpan|UnixTime|Enum|String|Object|Stream)$/i).nil?
|
64
|
+
payload = deserialize_primary_type(mapper, response_body)
|
65
|
+
elsif !mapper_type.match(/^Dictionary$/i).nil?
|
66
|
+
payload = deserialize_dictionary_type(mapper, response_body, object_name)
|
67
|
+
elsif !mapper_type.match(/^Composite$/i).nil?
|
68
|
+
payload = deserialize_composite_type(mapper, response_body, object_name)
|
69
|
+
elsif !mapper_type.match(/^Sequence$/i).nil?
|
70
|
+
payload = deserialize_sequence_type(mapper, response_body, object_name)
|
71
|
+
else
|
72
|
+
payload = ""
|
73
|
+
end
|
74
|
+
|
75
|
+
payload = mapper[:default_value] if mapper[:is_constant]
|
76
|
+
|
77
|
+
payload
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
# Deserialize the response of known primary type from the server using the mapper.
|
82
|
+
#
|
83
|
+
# @param mapper [Hash] Ruby Hash object to represent expected structure of the response_body.
|
84
|
+
# @param response_body [Hash] Ruby Hash object to deserialize.
|
85
|
+
#
|
86
|
+
def deserialize_primary_type(mapper, response_body)
|
87
|
+
result = ""
|
88
|
+
case mapper[:type][:name]
|
89
|
+
when 'Number'
|
90
|
+
result = Integer(response_body) unless response_body.to_s.empty?
|
91
|
+
when 'Double'
|
92
|
+
result = Float(response_body) unless response_body.to_s.empty?
|
93
|
+
when 'ByteArray'
|
94
|
+
result = Base64.strict_decode64(response_body).unpack('C*') unless response_body.to_s.empty?
|
95
|
+
when 'String', 'Boolean', 'Object', 'Stream', 'TimeSpan'
|
96
|
+
result = response_body
|
97
|
+
when 'Enum'
|
98
|
+
unless response_body.nil?
|
99
|
+
unless enum_is_valid(mapper, response_body)
|
100
|
+
warn "Enum does not contain #{response_body}, but was received from the server."
|
101
|
+
end
|
102
|
+
end
|
103
|
+
result = response_body
|
104
|
+
when 'Date'
|
105
|
+
unless response_body.to_s.empty?
|
106
|
+
result = Timeliness.parse(response_body, :strict => true)
|
107
|
+
fail DeserializationError.new('Error occured in deserializing the response_body', nil, nil, response_body) if result.nil?
|
108
|
+
result = ::Date.parse(result.to_s)
|
109
|
+
end
|
110
|
+
when 'DateTime', 'DateTimeRfc1123'
|
111
|
+
result = DateTime.parse(response_body) unless response_body.to_s.empty?
|
112
|
+
when 'UnixTime'
|
113
|
+
result = DateTime.strptime(response_body.to_s, '%s') unless response_body.to_s.empty?
|
114
|
+
else
|
115
|
+
result
|
116
|
+
end
|
117
|
+
result
|
118
|
+
end
|
119
|
+
|
120
|
+
#
|
121
|
+
# Deserialize the response of dictionary type from the server using the mapper.
|
122
|
+
#
|
123
|
+
# @param mapper [Hash] Ruby Hash object to represent expected structure of the response_body.
|
124
|
+
# @param response_body [Hash] Ruby Hash object to deserialize.
|
125
|
+
# @param object_name [String] Name of the deserialized object.
|
126
|
+
#
|
127
|
+
def deserialize_dictionary_type(mapper, response_body, object_name)
|
128
|
+
if mapper[:type][:value].nil? || !mapper[:type][:value].is_a?(Hash)
|
129
|
+
fail DeserializationError.new("'value' metadata for a dictionary type must be defined in the mapper and it must be of type Hash in #{object_name}", nil, nil, response_body)
|
130
|
+
end
|
131
|
+
|
132
|
+
result = Hash.new
|
133
|
+
response_body.each do |key, val|
|
134
|
+
result[key] = deserialize(mapper[:type][:value], val)
|
135
|
+
end
|
136
|
+
result
|
137
|
+
end
|
138
|
+
|
139
|
+
#
|
140
|
+
# Deserialize the response of composite type from the server using the mapper.
|
141
|
+
#
|
142
|
+
# @param mapper [Hash] Ruby Hash object to represent expected structure of the response_body.
|
143
|
+
# @param response_body [Hash] Ruby Hash object to deserialize.
|
144
|
+
# @param object_name [String] Name of the deserialized object.
|
145
|
+
#
|
146
|
+
def deserialize_composite_type(mapper, response_body, object_name)
|
147
|
+
if mapper[:type][:class_name].nil?
|
148
|
+
fail DeserializationError.new("'class_name' metadata for a composite type must be defined in the mapper and it must be of type Hash in #{object_name}", nil, nil, response_body)
|
149
|
+
end
|
150
|
+
|
151
|
+
if !mapper[:type][:polymorphic_discriminator].nil?
|
152
|
+
# Handle polymorphic types
|
153
|
+
parent_class = get_model(mapper[:type][:class_name])
|
154
|
+
discriminator = parent_class.class_eval("@@discriminatorMap")
|
155
|
+
model_name = response_body["#{mapper[:type][:polymorphic_discriminator]}"]
|
156
|
+
# In case we do not find model from response body then use the class defined in mapper
|
157
|
+
model_name = mapper[:type][:class_name] if model_name.nil? || model_name.empty?
|
158
|
+
model_class = get_model(discriminator[model_name])
|
159
|
+
else
|
160
|
+
model_class = get_model(mapper[:type][:class_name])
|
161
|
+
end
|
162
|
+
|
163
|
+
result = model_class.new
|
164
|
+
|
165
|
+
model_mapper = model_class.mapper()
|
166
|
+
model_props = model_mapper[:type][:model_properties]
|
167
|
+
|
168
|
+
unless model_props.nil?
|
169
|
+
model_props.each do |key, val|
|
170
|
+
sub_response_body = nil
|
171
|
+
unless val[:serialized_name].to_s.include? '.'
|
172
|
+
sub_response_body = response_body[val[:serialized_name].to_s]
|
173
|
+
else
|
174
|
+
# Flattened properties will be dicovered at deeper level in payload but must be deserialized to higher levels in model class
|
175
|
+
sub_response_body = response_body
|
176
|
+
levels = split_serialized_name(val[:serialized_name].to_s)
|
177
|
+
levels.each { |level| sub_response_body = sub_response_body.nil? ? nil : sub_response_body[level.to_s] }
|
178
|
+
end
|
179
|
+
|
180
|
+
result.instance_variable_set("@#{key}", deserialize(val, sub_response_body)) unless sub_response_body.nil?
|
181
|
+
end
|
182
|
+
end
|
183
|
+
result
|
184
|
+
end
|
185
|
+
|
186
|
+
#
|
187
|
+
# Deserialize the response of sequence type from the server using the mapper.
|
188
|
+
#
|
189
|
+
# @param mapper [Hash] Ruby Hash object to represent expected structure of the response_body.
|
190
|
+
# @param response_body [Hash] Ruby Hash object to deserialize.
|
191
|
+
# @param object_name [String] Name of the deserialized object.
|
192
|
+
#
|
193
|
+
def deserialize_sequence_type(mapper, response_body, object_name)
|
194
|
+
if mapper[:type][:element].nil? || !mapper[:type][:element].is_a?(Hash)
|
195
|
+
fail DeserializationError.new("'element' metadata for a sequence type must be defined in the mapper and it must be of type Hash in #{object_name}", nil, nil, response_body)
|
196
|
+
end
|
197
|
+
|
198
|
+
return response_body if response_body.nil?
|
199
|
+
|
200
|
+
result = []
|
201
|
+
response_body.each do |element|
|
202
|
+
result.push(deserialize(mapper[:type][:element], element))
|
203
|
+
end
|
204
|
+
|
205
|
+
result
|
206
|
+
end
|
207
|
+
|
208
|
+
#
|
209
|
+
# Serialize the Ruby object into Ruby Hash to send it to the server using the mapper.
|
210
|
+
#
|
211
|
+
# @param mapper [Hash] Ruby Hash object to represent expected structure of the object.
|
212
|
+
# @param object [Object] Ruby object to serialize.
|
213
|
+
# @param object_name [String] Name of the serialized object.
|
214
|
+
#
|
215
|
+
def serialize(mapper, object)
|
216
|
+
object_name = mapper[:serialized_name]
|
217
|
+
|
218
|
+
# Set defaults
|
219
|
+
unless mapper[:default_value].nil?
|
220
|
+
object = mapper[:default_value] if object.nil?
|
221
|
+
end
|
222
|
+
object = mapper[:default_value] if mapper[:is_constant]
|
223
|
+
|
224
|
+
validate_constraints(mapper, object, object_name)
|
225
|
+
|
226
|
+
if !mapper[:required] && object.nil?
|
227
|
+
return object
|
228
|
+
end
|
229
|
+
|
230
|
+
payload = Hash.new
|
231
|
+
mapper_type = mapper[:type][:name]
|
232
|
+
if !mapper_type.match(/^(Number|Double|ByteArray|Boolean|Date|DateTime|DateTimeRfc1123|TimeSpan|UnixTime|Enum|String|Object|Stream)$/i).nil?
|
233
|
+
payload = serialize_primary_type(mapper, object)
|
234
|
+
elsif !mapper_type.match(/^Dictionary$/i).nil?
|
235
|
+
payload = serialize_dictionary_type(mapper, object, object_name)
|
236
|
+
elsif !mapper_type.match(/^Composite$/i).nil?
|
237
|
+
payload = serialize_composite_type(mapper, object, object_name)
|
238
|
+
elsif !mapper_type.match(/^Sequence$/i).nil?
|
239
|
+
payload = serialize_sequence_type(mapper, object, object_name)
|
240
|
+
end
|
241
|
+
payload
|
242
|
+
end
|
243
|
+
|
244
|
+
def validate_constraints(mapper, object, object_name)
|
245
|
+
if(mapper[:client_side_validation])
|
246
|
+
# Throw if required & non-constant object is nil
|
247
|
+
if mapper[:required] && object.nil? && !mapper[:is_constant]
|
248
|
+
fail ValidationError, "#{object_name} is required and cannot be nil"
|
249
|
+
end
|
250
|
+
|
251
|
+
if(mapper[:constraints])
|
252
|
+
mapper[:constraints].each do |constraint_name, constraint_value|
|
253
|
+
case constraint_name.to_s.downcase
|
254
|
+
when 'exclusivemaximum'
|
255
|
+
fail ValidationError, "#{object_name} with value '#{object}' should satisfy the constraint 'ExclusiveMaximum': '#{constraint_value}'" if !object.nil? && object >= constraint_value
|
256
|
+
when 'exclusiveminimum'
|
257
|
+
fail ValidationError, "#{object_name} with value '#{object}' should satisfy the constraint 'ExclusiveMinimum': '#{constraint_value}'" if !object.nil? && object <= constraint_value
|
258
|
+
when 'inclusivemaximum'
|
259
|
+
fail ValidationError, "#{object_name} with value '#{object}' should satisfy the constraint 'InclusiveMaximum': '#{constraint_value}'" if !object.nil? && object > constraint_value
|
260
|
+
when 'inclusiveminimum'
|
261
|
+
fail ValidationError, "#{object_name} with value '#{object}' should satisfy the constraint 'InclusiveMinimum': '#{constraint_value}'" if !object.nil? && object < constraint_value
|
262
|
+
when 'maxitems'
|
263
|
+
fail ValidationError, "#{object_name} with value '#{object}' should satisfy the constraint 'MaxItems': '#{constraint_value}'" if !object.nil? && object.length > constraint_value
|
264
|
+
when 'minitems'
|
265
|
+
fail ValidationError, "#{object_name} with value '#{object}' should satisfy the constraint 'MinItems': '#{constraint_value}'" if !object.nil? && object.length < constraint_value
|
266
|
+
when 'maxlength'
|
267
|
+
fail ValidationError, "#{object_name} with value '#{object}' should satisfy the constraint 'MaxLength': '#{constraint_value}'" if !object.nil? && object.length > constraint_value
|
268
|
+
when 'minlength'
|
269
|
+
fail ValidationError, "#{object_name} with value '#{object}' should satisfy the constraint 'MinLength': '#{constraint_value}'" if !object.nil? && object.length < constraint_value
|
270
|
+
when 'multipleof'
|
271
|
+
fail ValidationError, "#{object_name} with value '#{object}' should satisfy the constraint 'MultipleOf': '#{constraint_value}'" if !object.nil? && object % constraint_value != 0
|
272
|
+
when 'pattern'
|
273
|
+
fail ValidationError, "#{object_name} with value '#{object}' should satisfy the constraint 'Pattern': '#{constraint_value}'" if !object.nil? && object.match(Regexp.new "^#{constraint_value}$").nil?
|
274
|
+
when 'uniqueitems'
|
275
|
+
fail ValidationError, "#{object_name} with value '#{object}' should satisfy the constraint 'UniqueItems': '#{constraint_value}'" if !object.nil? && object.length != object.uniq.length
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
#
|
283
|
+
# Serialize the Ruby object of known primary type into Ruby Hash to send it to the server using the mapper.
|
284
|
+
#
|
285
|
+
# @param mapper [Hash] Ruby Hash object to represent expected structure of the object.
|
286
|
+
# @param object [Object] Ruby object to serialize.
|
287
|
+
#
|
288
|
+
def serialize_primary_type(mapper, object)
|
289
|
+
mapper_type = mapper[:type][:name]
|
290
|
+
payload = nil
|
291
|
+
case mapper_type
|
292
|
+
when 'Number', 'Double', 'String', 'Date', 'TimeSpan', 'Boolean', 'Object', 'Stream'
|
293
|
+
payload = object != nil ? object : nil
|
294
|
+
when 'Enum'
|
295
|
+
unless object.nil?
|
296
|
+
unless enum_is_valid(mapper, object)
|
297
|
+
fail ValidationError, "Enum #{mapper[:type][:module]} does not contain #{object.to_s}, but trying to send it to the server."
|
298
|
+
end
|
299
|
+
end
|
300
|
+
payload = object != nil ? object : nil
|
301
|
+
when 'ByteArray'
|
302
|
+
payload = Base64.strict_encode64(object.pack('c*'))
|
303
|
+
when 'DateTime'
|
304
|
+
payload = object.new_offset(0).strftime('%FT%TZ')
|
305
|
+
when 'DateTimeRfc1123'
|
306
|
+
payload = object.new_offset(0).strftime('%a, %d %b %Y %H:%M:%S GMT')
|
307
|
+
when 'UnixTime'
|
308
|
+
payload = object.new_offset(0).strftime('%s') unless object.nil?
|
309
|
+
end
|
310
|
+
payload
|
311
|
+
end
|
312
|
+
|
313
|
+
#
|
314
|
+
# Serialize the Ruby object of dictionary type into Ruby Hash to send it to the server using the mapper.
|
315
|
+
#
|
316
|
+
# @param mapper [Hash] Ruby Hash object to represent expected structure of the object.
|
317
|
+
# @param object [Object] Ruby object to serialize.
|
318
|
+
# @param object_name [String] Name of the serialized object.
|
319
|
+
#
|
320
|
+
def serialize_dictionary_type(mapper, object, object_name)
|
321
|
+
unless object.is_a?(Hash)
|
322
|
+
fail DeserializationError.new("#{object_name} must be of type Hash", nil, nil, object)
|
323
|
+
end
|
324
|
+
|
325
|
+
unless mapper[:type][:value].nil? || mapper[:type][:value].is_a?(Hash)
|
326
|
+
fail DeserializationError.new("'value' metadata for a dictionary type must be defined in the mapper and it must be of type Hash in #{object_name}", nil, nil, object)
|
327
|
+
end
|
328
|
+
|
329
|
+
payload = Hash.new
|
330
|
+
object.each do |key, value|
|
331
|
+
if !value.nil? && value.respond_to?(:validate)
|
332
|
+
value.validate
|
333
|
+
end
|
334
|
+
|
335
|
+
payload[key] = serialize(mapper[:type][:value], value)
|
336
|
+
end
|
337
|
+
payload
|
338
|
+
end
|
339
|
+
|
340
|
+
#
|
341
|
+
# Serialize the Ruby object of composite type into Ruby Hash to send it to the server using the mapper.
|
342
|
+
#
|
343
|
+
# @param mapper [Hash] Ruby Hash object to represent expected structure of the object.
|
344
|
+
# @param object [Object] Ruby object to serialize.
|
345
|
+
# @param object_name [String] Name of the serialized object.
|
346
|
+
#
|
347
|
+
def serialize_composite_type(mapper, object, object_name)
|
348
|
+
if !mapper[:type][:polymorphic_discriminator].nil?
|
349
|
+
# Handle polymorphic types
|
350
|
+
model_name = object.class.to_s.split('::')[-1]
|
351
|
+
model_class = get_model(model_name)
|
352
|
+
else
|
353
|
+
model_class = get_model(mapper[:type][:class_name])
|
354
|
+
end
|
355
|
+
|
356
|
+
payload = Hash.new
|
357
|
+
model_mapper = model_class.mapper()
|
358
|
+
model_props = model_mapper[:type][:model_properties]
|
359
|
+
|
360
|
+
unless model_props.nil?
|
361
|
+
model_props.each do |key, value|
|
362
|
+
begin
|
363
|
+
instance_variable = object.instance_variable_get("@#{key}")
|
364
|
+
rescue NameError
|
365
|
+
warn("Instance variable '#{key}' is expected on '#{object.class}'.")
|
366
|
+
end
|
367
|
+
|
368
|
+
if !instance_variable.nil? && instance_variable.respond_to?(:validate)
|
369
|
+
instance_variable.validate
|
370
|
+
end
|
371
|
+
|
372
|
+
# Read only properties should not be sent on wire
|
373
|
+
if !model_props[key][:read_only].nil? && model_props[key][:read_only]
|
374
|
+
next
|
375
|
+
end
|
376
|
+
|
377
|
+
sub_payload = serialize(value, instance_variable)
|
378
|
+
|
379
|
+
unless value[:serialized_name].to_s.include? '.'
|
380
|
+
payload[value[:serialized_name].to_s] = sub_payload unless sub_payload.nil?
|
381
|
+
else
|
382
|
+
# Flattened properties will be discovered at higher levels in model class but must be serialized to deeper level in payload
|
383
|
+
levels = split_serialized_name(value[:serialized_name].to_s)
|
384
|
+
last_level = levels.pop
|
385
|
+
temp_payload = payload
|
386
|
+
levels.each do |level|
|
387
|
+
temp_payload[level] = Hash.new unless temp_payload.key?(level)
|
388
|
+
temp_payload = temp_payload[level]
|
389
|
+
end
|
390
|
+
temp_payload[last_level] = sub_payload unless sub_payload.nil?
|
391
|
+
end
|
392
|
+
end
|
393
|
+
end
|
394
|
+
payload
|
395
|
+
end
|
396
|
+
|
397
|
+
#
|
398
|
+
# Serialize the Ruby object of sequence type into Ruby Hash to send it to the server using the mapper.
|
399
|
+
#
|
400
|
+
# @param mapper [Hash] Ruby Hash object to represent expected structure of the object.
|
401
|
+
# @param object [Object] Ruby object to serialize.
|
402
|
+
# @param object_name [String] Name of the serialized object.
|
403
|
+
#
|
404
|
+
def serialize_sequence_type(mapper, object, object_name)
|
405
|
+
unless object.is_a?(Array)
|
406
|
+
fail DeserializationError.new("#{object_name} must be of type of Array", nil, nil, object)
|
407
|
+
end
|
408
|
+
|
409
|
+
unless mapper[:type][:element].nil? || mapper[:type][:element].is_a?(Hash)
|
410
|
+
fail DeserializationError.new("'element' metadata for a sequence type must be defined in the mapper and it must be of type Hash in #{object_name}", nil, nil, object)
|
411
|
+
end
|
412
|
+
|
413
|
+
payload = Array.new
|
414
|
+
object.each do |element|
|
415
|
+
if !element.nil? && element.respond_to?(:validate)
|
416
|
+
element.validate
|
417
|
+
end
|
418
|
+
payload.push(serialize(mapper[:type][:element], element))
|
419
|
+
end
|
420
|
+
payload
|
421
|
+
end
|
422
|
+
|
423
|
+
#
|
424
|
+
# Retrieves model of the model_name
|
425
|
+
#
|
426
|
+
# @param model_name [String] Name of the model to retrieve.
|
427
|
+
#
|
428
|
+
def get_model(model_name)
|
429
|
+
begin
|
430
|
+
consts = @context.class.to_s.split('::')
|
431
|
+
end_index = 0
|
432
|
+
if consts.any?{ |const| const == 'Models' }
|
433
|
+
# context is a model class
|
434
|
+
end_index = -2
|
435
|
+
else
|
436
|
+
# context is a service, so find the model class
|
437
|
+
end_index = -1
|
438
|
+
end
|
439
|
+
Object.const_get(consts[0...end_index].join('::') + "::Models::#{model_name}")
|
440
|
+
rescue
|
441
|
+
Object.const_get("MsRestAzure::#{model_name}")
|
442
|
+
end
|
443
|
+
end
|
444
|
+
|
445
|
+
#
|
446
|
+
# Checks whether given enum_value is valid for the mapper or not
|
447
|
+
#
|
448
|
+
# @param mapper [Hash] Ruby Hash object containing meta data
|
449
|
+
# @param enum_value [String] Enum value to validate
|
450
|
+
#
|
451
|
+
def enum_is_valid(mapper, enum_value)
|
452
|
+
if enum_value.is_a?(String) && !enum_value.empty?
|
453
|
+
model = get_model(mapper[:type][:module])
|
454
|
+
model.constants.any? { |e| model.const_get(e).to_s.downcase == enum_value.downcase }
|
455
|
+
else
|
456
|
+
false
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
# Splits serialized_name with '.' to compute levels of object hierarchy
|
461
|
+
#
|
462
|
+
# @param serialized_name [String] Name to split
|
463
|
+
#
|
464
|
+
def split_serialized_name(serialized_name)
|
465
|
+
result = Array.new
|
466
|
+
element = ''
|
467
|
+
|
468
|
+
levels = serialized_name.to_s.split('.')
|
469
|
+
levels.each do |level|
|
470
|
+
unless level.match(/.*\\$/).nil?
|
471
|
+
# Flattened properties will be discovered at different levels in model class and response body
|
472
|
+
element = "#{element}#{level.gsub!('\\','')}."
|
473
|
+
else
|
474
|
+
element = "#{element}#{level}"
|
475
|
+
result.push(element) unless element.empty?
|
476
|
+
element = ''
|
477
|
+
end
|
478
|
+
end
|
479
|
+
result
|
480
|
+
end
|
481
|
+
end
|
482
|
+
end
|
483
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for license information.
|
4
|
+
|
5
|
+
module MsRest
|
6
|
+
#
|
7
|
+
# Class which represents a point of access to the REST API.
|
8
|
+
#
|
9
|
+
class ServiceClient
|
10
|
+
|
11
|
+
# @return [MsRest::ServiceClientCredentials] the credentials object.
|
12
|
+
attr_accessor :credentials
|
13
|
+
|
14
|
+
# @return [Hash{String=>String}] default middlewares configuration for requests.
|
15
|
+
attr_accessor :middlewares
|
16
|
+
|
17
|
+
# @return [Hash{String=>String}] default request headers for requests.
|
18
|
+
attr_accessor :request_headers
|
19
|
+
|
20
|
+
# @return [Array] strings to be appended to the user agent in the request
|
21
|
+
attr_accessor :user_agent_extended
|
22
|
+
|
23
|
+
#
|
24
|
+
# Creates and initialize new instance of the ServiceClient class.
|
25
|
+
#
|
26
|
+
# @param credentials [MsRest::ServiceClientCredentials] credentials to authorize
|
27
|
+
# HTTP requests made by the service client.
|
28
|
+
# @param options additional parameters for the HTTP request (not implemented yet).
|
29
|
+
#
|
30
|
+
def initialize(credentials = nil, options = nil)
|
31
|
+
@credentials = credentials
|
32
|
+
@request_headers = {}
|
33
|
+
@middlewares = {middlewares: [[MsRest::RetryPolicyMiddleware, times: 3, retry: 0.02], [:cookie_jar]]}
|
34
|
+
@user_agent_extended = []
|
35
|
+
@user_agent_extended.push("ms_rest/#{MsRest::VERSION}")
|
36
|
+
end
|
37
|
+
|
38
|
+
#
|
39
|
+
# @param base_url [String] the base url for the request.
|
40
|
+
# @param method [Symbol] with any of the following values :get, :put, :post, :patch, :delete.
|
41
|
+
# @param path [String] the path, relative to {base_url}.
|
42
|
+
# @param options [Hash{String=>String}] specifying any request options like :credentials, :body, etc.
|
43
|
+
# @return [Concurrent::Promise] Promise object which holds the HTTP response.
|
44
|
+
#
|
45
|
+
def make_request_async(base_url, method, path, options = {})
|
46
|
+
options = @middlewares.merge(options)
|
47
|
+
options[:credentials] = options[:credentials] || @credentials
|
48
|
+
options[:user_agent_extended] = @user_agent_extended
|
49
|
+
request = MsRest::HttpOperationRequest.new(base_url, path, method, options)
|
50
|
+
promise = request.run_promise do |req|
|
51
|
+
options[:credentials].sign_request(req) unless options[:credentials].nil?
|
52
|
+
end
|
53
|
+
promise = promise.then do |http_response|
|
54
|
+
response_content = http_response.body.to_s.empty? ? nil : http_response.body
|
55
|
+
# Create response
|
56
|
+
create_response(request, http_response, response_content)
|
57
|
+
end
|
58
|
+
promise.execute
|
59
|
+
end
|
60
|
+
|
61
|
+
#
|
62
|
+
# Add additional information into User-Agent header.
|
63
|
+
# @param [String] additional_user_agent_information additional product information for user agent string.
|
64
|
+
#
|
65
|
+
# Example:
|
66
|
+
# recommended format is Product/[version]
|
67
|
+
# please refer https://github.com/Azure/azure-sdk-for-ruby/issues/517 for more information.
|
68
|
+
#
|
69
|
+
# add_user_agent_information('fog-azure-rm/0.2.0')
|
70
|
+
#
|
71
|
+
def add_user_agent_information(additional_user_agent_information)
|
72
|
+
@user_agent_extended.push(additional_user_agent_information)
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
#
|
77
|
+
# Retrieves a new instance of the HttpOperationResponse class.
|
78
|
+
# @param [MsRest::HttpOperationRequest] request the HTTP request object.
|
79
|
+
# @param [Faraday::Response] response the HTTP response object.
|
80
|
+
# @param [String] body the HTTP response body.
|
81
|
+
# @return [MsRest::HttpOperationResponse] the operation response.
|
82
|
+
#
|
83
|
+
def create_response(request, http_response, body = nil)
|
84
|
+
HttpOperationResponse.new(request, http_response, body)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
#
|
89
|
+
# Hash of SSL options for Faraday connection. Default is nil.
|
90
|
+
#
|
91
|
+
@@ssl_options = {}
|
92
|
+
|
93
|
+
#
|
94
|
+
# Stores the SSL options to be used for Faraday connections.
|
95
|
+
# ==== Examples
|
96
|
+
# MsRest.use_ssl_cert # => Uses bundled certificate for all the connections
|
97
|
+
# MsRest.use_ssl_cert({:ca_file => "path_to_ca_file"}) # => Uses supplied certificate for all the connections
|
98
|
+
#
|
99
|
+
# @param ssl_options [Hash] Hash of SSL options for Faraday connection. It defaults to the bundled certificate.
|
100
|
+
#
|
101
|
+
def self.use_ssl_cert(ssl_options = nil)
|
102
|
+
if ssl_options.nil?
|
103
|
+
@@ssl_options = {:ca_file => File.expand_path(File.join(File.dirname(__FILE__), '../..', 'ca-cert.pem')) }
|
104
|
+
else
|
105
|
+
@@ssl_options = ssl_options
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
#
|
110
|
+
# @return [Hash] Hash of SSL options to be used for Faraday connection.
|
111
|
+
#
|
112
|
+
def self.ssl_options
|
113
|
+
@@ssl_options
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for license information.
|
4
|
+
|
5
|
+
module MsRest
|
6
|
+
#
|
7
|
+
# Class which represents an error meaning that invalid Model object was created by user or provided from server.
|
8
|
+
#
|
9
|
+
class ValidationError < RestError
|
10
|
+
end
|
11
|
+
end
|
data/lib/ms_rest.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for license information.
|
4
|
+
|
5
|
+
require 'base64'
|
6
|
+
require 'openssl'
|
7
|
+
require 'faraday'
|
8
|
+
require 'timeliness'
|
9
|
+
require 'ms_rest/version'
|
10
|
+
|
11
|
+
require 'ms_rest/credentials/token_provider'
|
12
|
+
require 'ms_rest/credentials/string_token_provider'
|
13
|
+
require 'ms_rest/credentials/service_client_credentials'
|
14
|
+
require 'ms_rest/credentials/basic_authentication_credentials'
|
15
|
+
require 'ms_rest/credentials/token_credentials'
|
16
|
+
|
17
|
+
require 'ms_rest/rest_error.rb'
|
18
|
+
require 'ms_rest/deserialization_error.rb'
|
19
|
+
require 'ms_rest/validation_error.rb'
|
20
|
+
require 'ms_rest/serialization.rb'
|
21
|
+
require 'ms_rest/http_operation_response'
|
22
|
+
require 'ms_rest/http_operation_request'
|
23
|
+
require 'ms_rest/http_operation_error'
|
24
|
+
require 'ms_rest/retry_policy_middleware'
|
25
|
+
require 'ms_rest/service_client'
|
26
|
+
require 'ms_rest/jsonable'
|
27
|
+
|
28
|
+
module MsRest end
|
29
|
+
module MsRest::Serialization end
|