| 
									
										
										
										
											2015-04-17 00:28:38 +00:00
										 |  |  | # Copyright 2015 Google Inc. | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  | # you may not use this file except in compliance with the License. | 
					
						
							|  |  |  | # You may obtain a copy of the License at | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | #      http://www.apache.org/licenses/LICENSE-2.0 | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  | # distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  | # See the License for the specific language governing permissions and | 
					
						
							|  |  |  | # limitations under the License. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | require 'addressable/uri' | 
					
						
							|  |  |  | require 'addressable/template' | 
					
						
							|  |  |  | require 'google/apis/core/http_command' | 
					
						
							|  |  |  | require 'google/apis/errors' | 
					
						
							| 
									
										
										
										
											2016-02-25 02:27:33 +00:00
										 |  |  | require 'json' | 
					
						
							| 
									
										
										
										
											2015-04-17 00:28:38 +00:00
										 |  |  | require 'retriable' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module Google | 
					
						
							|  |  |  |   module Apis | 
					
						
							|  |  |  |     module Core | 
					
						
							|  |  |  |       # Command for executing most basic API request with JSON requests/responses | 
					
						
							|  |  |  |       class ApiCommand < HttpCommand | 
					
						
							|  |  |  |         JSON_CONTENT_TYPE = 'application/json' | 
					
						
							|  |  |  |         FIELDS_PARAM = 'fields' | 
					
						
							| 
									
										
										
										
											2017-02-02 07:20:19 +00:00
										 |  |  |         ERROR_REASON_MAPPING = { | 
					
						
							|  |  |  |           'rateLimitExceeded' => Google::Apis::RateLimitError, | 
					
						
							|  |  |  |           'userRateLimitExceeded' => Google::Apis::RateLimitError, | 
					
						
							|  |  |  |           'projectNotLinked' => Google::Apis::ProjectNotLinkedError | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2015-04-17 00:28:38 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # JSON serializer for request objects | 
					
						
							|  |  |  |         # @return [Google::Apis::Core::JsonRepresentation] | 
					
						
							|  |  |  |         attr_accessor :request_representation | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Request body to serialize | 
					
						
							|  |  |  |         # @return [Object] | 
					
						
							|  |  |  |         attr_accessor :request_object | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # JSON serializer for response objects | 
					
						
							|  |  |  |         # @return [Google::Apis::Core::JsonRepresentation] | 
					
						
							|  |  |  |         attr_accessor :response_representation | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Class to instantiate when de-serializing responses | 
					
						
							|  |  |  |         # @return [Object] | 
					
						
							|  |  |  |         attr_accessor :response_class | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Serialize the request body | 
					
						
							|  |  |  |         # | 
					
						
							|  |  |  |         # @return [void] | 
					
						
							|  |  |  |         def prepare! | 
					
						
							| 
									
										
										
										
											2017-05-19 23:16:22 +00:00
										 |  |  |           if options && options.api_format_version | 
					
						
							|  |  |  |             header['X-Goog-Api-Format-Version'] = options.api_format_version.to_s | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2015-04-17 00:28:38 +00:00
										 |  |  |           query[FIELDS_PARAM] = normalize_fields_param(query[FIELDS_PARAM]) if query.key?(FIELDS_PARAM) | 
					
						
							|  |  |  |           if request_representation && request_object | 
					
						
							| 
									
										
										
										
											2016-08-17 20:51:09 +00:00
										 |  |  |             header['Content-Type'] ||= JSON_CONTENT_TYPE | 
					
						
							| 
									
										
										
										
											2017-03-31 22:26:51 +00:00
										 |  |  |             if options && options.skip_serialization | 
					
						
							|  |  |  |               self.body = request_object | 
					
						
							|  |  |  |             else | 
					
						
							|  |  |  |               self.body = request_representation.new(request_object).to_json(user_options: { skip_undefined: true }) | 
					
						
							|  |  |  |             end | 
					
						
							| 
									
										
										
										
											2015-04-17 00:28:38 +00:00
										 |  |  |           end | 
					
						
							|  |  |  |           super | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Deserialize the response body if present | 
					
						
							|  |  |  |         # | 
					
						
							|  |  |  |         # @param [String] content_type | 
					
						
							|  |  |  |         #  Content type of body | 
					
						
							|  |  |  |         # @param [String, #read] body | 
					
						
							|  |  |  |         #  Response body | 
					
						
							|  |  |  |         # @return [Object] | 
					
						
							|  |  |  |         #   Response object | 
					
						
							|  |  |  |         # noinspection RubyUnusedLocalVariable | 
					
						
							|  |  |  |         def decode_response_body(content_type, body) | 
					
						
							|  |  |  |           return super unless response_representation | 
					
						
							| 
									
										
										
										
											2017-03-31 22:26:51 +00:00
										 |  |  |           return super if options && options.skip_deserialization | 
					
						
							| 
									
										
										
										
											2015-04-17 00:28:38 +00:00
										 |  |  |           return super if content_type.nil? | 
					
						
							|  |  |  |           return nil unless content_type.start_with?(JSON_CONTENT_TYPE) | 
					
						
							|  |  |  |           instance = response_class.new | 
					
						
							|  |  |  |           response_representation.new(instance).from_json(body, unwrap: response_class) | 
					
						
							|  |  |  |           instance | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Check the response and raise error if needed | 
					
						
							|  |  |  |         # | 
					
						
							|  |  |  |         # @param [Fixnum] status | 
					
						
							|  |  |  |         #   HTTP status code of response | 
					
						
							| 
									
										
										
										
											2016-08-17 20:51:09 +00:00
										 |  |  |         # @param [Hash] header | 
					
						
							| 
									
										
										
										
											2015-07-20 19:36:13 +00:00
										 |  |  |         #   HTTP response headers | 
					
						
							| 
									
										
										
										
											2015-04-17 00:28:38 +00:00
										 |  |  |         # @param [String] body | 
					
						
							|  |  |  |         #   HTTP response body | 
					
						
							| 
									
										
										
										
											2015-07-20 19:36:13 +00:00
										 |  |  |         # @param [String] message | 
					
						
							|  |  |  |         #   Error message text | 
					
						
							| 
									
										
										
										
											2015-04-17 00:28:38 +00:00
										 |  |  |         # @return [void] | 
					
						
							|  |  |  |         # @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried | 
					
						
							|  |  |  |         # @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification | 
					
						
							|  |  |  |         # @raise [Google::Apis::AuthorizationError] Authorization is required | 
					
						
							| 
									
										
										
										
											2015-07-20 19:36:13 +00:00
										 |  |  |         def check_status(status, header = nil, body = nil, message = nil) | 
					
						
							| 
									
										
										
										
											2015-04-17 00:28:38 +00:00
										 |  |  |           case status | 
					
						
							|  |  |  |           when 400, 402...500
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:16:22 +00:00
										 |  |  |             reason, message = parse_error(body) | 
					
						
							|  |  |  |             if reason | 
					
						
							|  |  |  |               message = sprintf('%s: %s', reason, message) | 
					
						
							|  |  |  |               raise ERROR_REASON_MAPPING[reason].new( | 
					
						
							| 
									
										
										
										
											2017-02-02 07:20:19 +00:00
										 |  |  |                 message, | 
					
						
							|  |  |  |                 status_code: status, | 
					
						
							|  |  |  |                 header: header, | 
					
						
							|  |  |  |                 body: body | 
					
						
							| 
									
										
										
										
											2017-05-19 23:16:22 +00:00
										 |  |  |               ) if ERROR_REASON_MAPPING.key?(reason) | 
					
						
							| 
									
										
										
										
											2015-04-17 00:28:38 +00:00
										 |  |  |             end | 
					
						
							| 
									
										
										
										
											2015-07-20 19:36:13 +00:00
										 |  |  |             super(status, header, body, message) | 
					
						
							| 
									
										
										
										
											2015-04-17 00:28:38 +00:00
										 |  |  |           else | 
					
						
							| 
									
										
										
										
											2015-07-20 19:36:13 +00:00
										 |  |  |             super(status, header, body, message) | 
					
						
							| 
									
										
										
										
											2015-04-17 00:28:38 +00:00
										 |  |  |           end | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-08 20:40:30 +00:00
										 |  |  |         def allow_form_encoding? | 
					
						
							|  |  |  |           request_representation.nil? && super | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-17 00:28:38 +00:00
										 |  |  |         private | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:16:22 +00:00
										 |  |  |         # Attempt to parse a JSON error message | 
					
						
							| 
									
										
										
										
											2015-04-17 00:28:38 +00:00
										 |  |  |         # @param [String] body | 
					
						
							|  |  |  |         #  HTTP response body | 
					
						
							| 
									
										
										
										
											2017-05-19 23:16:22 +00:00
										 |  |  |         # @return [Array<(String, String)>] | 
					
						
							|  |  |  |         #   Error reason and message | 
					
						
							| 
									
										
										
										
											2015-04-17 00:28:38 +00:00
										 |  |  |         def parse_error(body) | 
					
						
							| 
									
										
										
										
											2017-05-19 23:16:22 +00:00
										 |  |  |           obj = JSON.load(body) | 
					
						
							|  |  |  |           error = obj['error'] | 
					
						
							|  |  |  |           if error['details'] | 
					
						
							|  |  |  |             return extract_v2_error_details(error) | 
					
						
							|  |  |  |           elsif error['errors'] | 
					
						
							|  |  |  |             return extract_v1_error_details(error) | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |             fail 'Can not parse error message. No "details" or "errors" detected' | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2015-04-17 00:28:38 +00:00
										 |  |  |         rescue | 
					
						
							| 
									
										
										
										
											2017-05-19 23:16:22 +00:00
										 |  |  |           return [nil, nil] | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Extracts details from a v1 error message | 
					
						
							|  |  |  |         # @param [Hash] error | 
					
						
							|  |  |  |         #  Parsed JSON | 
					
						
							|  |  |  |         # @return [Array<(String, String)>] | 
					
						
							|  |  |  |         #   Error reason and message | 
					
						
							|  |  |  |         def extract_v1_error_details(error) | 
					
						
							|  |  |  |           reason = error['errors'].first['reason'] | 
					
						
							|  |  |  |           message = error['message'] | 
					
						
							|  |  |  |           return [reason, message] | 
					
						
							|  |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Extracts details from a v2error message | 
					
						
							|  |  |  |         # @param [Hash] error | 
					
						
							|  |  |  |         #  Parsed JSON | 
					
						
							|  |  |  |         # @return [Array<(String, String)>] | 
					
						
							|  |  |  |         #   Error reason and message | 
					
						
							|  |  |  |         def extract_v2_error_details(error) | 
					
						
							|  |  |  |           reason = error['status'] | 
					
						
							|  |  |  |           message = error['message'] | 
					
						
							|  |  |  |           return [reason, message] | 
					
						
							| 
									
										
										
										
											2015-04-17 00:28:38 +00:00
										 |  |  |         end | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Convert field names from ruby conventions to original names in JSON | 
					
						
							|  |  |  |         # | 
					
						
							|  |  |  |         # @param [String] fields | 
					
						
							|  |  |  |         #   Value of 'fields' param | 
					
						
							|  |  |  |         # @return [String] | 
					
						
							|  |  |  |         #   Updated header value | 
					
						
							|  |  |  |         def normalize_fields_param(fields) | 
					
						
							|  |  |  |           # TODO: Generate map of parameter names during code gen. Small possibility that camelization fails | 
					
						
							| 
									
										
										
										
											2016-02-25 21:06:16 +00:00
										 |  |  |           fields.gsub(/:/, '').gsub(/\w+/) do |str| | 
					
						
							|  |  |  |             str.gsub(/(?:^|_)([a-z])/){ Regexp.last_match.begin(0) == 0 ? $1 : $1.upcase } | 
					
						
							|  |  |  |           end | 
					
						
							| 
									
										
										
										
											2015-04-17 00:28:38 +00:00
										 |  |  |         end | 
					
						
							|  |  |  |       end | 
					
						
							|  |  |  |     end | 
					
						
							|  |  |  |   end | 
					
						
							|  |  |  | end |