class Scorpio::Request
Constants
- FALLBACK_CONTENT_TYPE
- SUPPORTED_REQUEST_MEDIA_TYPES
Attributes
@return [Scorpio::OpenAPI::Operation]
Public Class Methods
# File lib/scorpio/request.rb, line 6 def self.best_media_type(media_types) if media_types.size == 1 media_types.first else SUPPORTED_REQUEST_MEDIA_TYPES.detect { |mt| media_types.include?(mt) } end end
@param operation [Scorpio::OpenAPI::Operation] @param configuration [#to_hash] a hash keyed with configurable attributes for
the request - instance methods of Scorpio::Request::Configurables, whose values will be assigned for those attributes.
# File lib/scorpio/request.rb, line 118 def initialize(operation, configuration = {}, &b) @operation = operation configuration = JSI.stringify_symbol_keys(configuration) params_set = Set.new # the set of params that have been set # do the Configurables first configuration.each do |name, value| if Configurables.public_method_defined?("#{name}=") Configurables.instance_method("#{name}=").bind(self).call(value) params_set << name end end # then do other top-level params configuration.reject { |name, _| params_set.include?(name) }.each do |name, value| param = param_for(name) || raise(ArgumentError, "unrecognized configuration value passed: #{name.inspect}") set_param_from(param['in'], param['name'], value) end extend operation.request_accessor_module if block_given? yield self end end
Public Instance Methods
@return [::Ur::ContentType] Content-Type for this request, taken from request headers if
present, or the request media_type.
# File lib/scorpio/request.rb, line 204 def content_type content_type_header || (media_type ? ::Ur::ContentType.new(media_type) : nil) end
@return [::Ur::ContentType] the value of the request Content-Type header
# File lib/scorpio/request.rb, line 195 def content_type_header headers.each do |k, v| return ::Ur::ContentType.new(v) if k =~ /\Acontent[-_]type\z/i end nil end
todo make a proper iterator interface @param next_page [#call] a callable which will take a parameter `page_ur`, which is a {Scorpio::Ur},
and must result in an Ur representing the next page, which will be yielded to the block.
@yield [Scorpio::Ur] yields the first page, and each subsequent result of calls to `next_page` until
that results in nil
@return [void]
# File lib/scorpio/request.rb, line 359 def each_page_ur(next_page: , raise_on_http_error: true) return to_enum(__method__, next_page: next_page, raise_on_http_error: raise_on_http_error) unless block_given? page_ur = run_ur while page_ur page_ur.raise_on_http_error if raise_on_http_error yield page_ur page_ur = next_page.call(page_ur) end nil end
builds a Faraday connection with this Request's faraday_builder and faraday_adapter. passes a given proc yield_ur to middleware to yield an Ur
for requests made with the connection.
@param yield_ur [Proc] @return [::Faraday::Connection]
# File lib/scorpio/request.rb, line 218 def faraday_connection(yield_ur = nil) Faraday.new do |faraday_connection| faraday_builder.call(faraday_connection) if yield_ur -> { ::Ur::Faraday }.() # autoload trigger faraday_connection.response(:yield_ur, schemas: Set[Scorpio::Ur.schema], logger: self.logger, &yield_ur) end faraday_connection.adapter(*faraday_adapter) end end
@param name [String, Symbol] the 'name' property of one applicable parameter @return [Object] the value of the named parameter on this request @raise [Scorpio::AmbiguousParameter] if more than one parameter has the given name
# File lib/scorpio/request.rb, line 245 def get_param(name) param = param_for!(name) get_param_from(param['in'], param['name']) end
@param in [String, Symbol] one of 'path', 'query', 'header', or 'cookie' - where to apply the named value @param name [String, Symbol] the parameter name @return [Object] the value of the named parameter on this request @raise [ArgumentError] invalid 'in' parameter @raise [NotImplementedError] cookies aren't implemented
# File lib/scorpio/request.rb, line 300 def get_param_from(param_in, name) if param_in == 'path' path_params[name] elsif param_in == 'query' query_params ? query_params[name] : nil elsif param_in == 'header' _, value = headers.detect { |headername, _| headername.downcase == name.downcase } value elsif param_in == 'cookie' raise(NotImplementedError, "cookies not implemented: #{name.inspect}") else raise(ArgumentError, "cannot get param from param_in = #{param_in.inspect} (name: #{name.pretty_inspect.chomp})") end end
@return [Symbol] the http method for this request - :get, :post, etc.
# File lib/scorpio/request.rb, line 152 def http_method operation.http_method.downcase.to_sym end
@return [Scorpio::OpenAPI::Document]
# File lib/scorpio/request.rb, line 147 def openapi_document operation.openapi_document end
@param name [String, Symbol] the 'name' property of one applicable parameter @return [#to_hash, nil]
# File lib/scorpio/request.rb, line 252 def param_for(name) name = name.to_s if name.is_a?(Symbol) params = operation.inferred_parameters.select { |p| p['name'] == name } if params.size == 1 params.first elsif params.size == 0 nil else raise(AmbiguousParameter.new( "There are multiple parameters for #{name}. matched parameters were: #{params.pretty_inspect.chomp}" ).tap { |e| e.name = name }) end end
@param name [String, Symbol] the name or {in}.{name} (e.g. “query.search”) for the applicable parameter. @return [#to_hash]
# File lib/scorpio/request.rb, line 268 def param_for!(name) param_for(name) || raise(ParameterError, "There is no parameter named #{name} on operation #{operation.human_id}:\n#{operation.pretty_inspect.chomp}") end
@return [Addressable::URI] an Addressable::URI containing only the path to append to
the base_url for this request
# File lib/scorpio/request.rb, line 164 def path path_params = JSI.stringify_symbol_keys(self.path_params) missing_variables = path_template.variables - path_params.keys if missing_variables.any? raise(ArgumentError, "path #{operation.path_template_str} for operation #{operation.human_id} requires path_params " + "which were missing: #{missing_variables.inspect}") end empty_variables = path_template.variables.select { |v| path_params[v].to_s.empty? } if empty_variables.any? raise(ArgumentError, "path #{operation.path_template_str} for operation #{operation.human_id} requires path_params " + "which were empty: #{empty_variables.inspect}") end path_template.expand(path_params).tap do |path| if query_params path.query_values = query_params end end end
@return [Addressable::Template] the template for the request's path, to be expanded
with path_params and appended to the request's base_url
# File lib/scorpio/request.rb, line 158 def path_template operation.path_template end
@return [::JSI::Schema]
# File lib/scorpio/request.rb, line 209 def request_schema(media_type: self.media_type) operation.request_schema(media_type: media_type) end
runs this request. returns the response body object - that is, the response body parsed according to an understood media type, and instantiated with the applicable response schema if one is specified. see Scorpio::Response#body_object
for more detail.
@raise [Scorpio::HTTPError] if the request returns a 4xx or 5xx status, the appropriate
error is raised - see Scorpio::HTTPErrors
# File lib/scorpio/request.rb, line 347 def run ur = run_ur ur.raise_on_http_error ur.response.body_object end
runs this request and returns the full representation of the request that was run and its response.
@return [Scorpio::Ur]
# File lib/scorpio/request.rb, line 318 def run_ur headers = {} if user_agent headers['User-Agent'] = user_agent end if !content_type_header if media_type headers['Content-Type'] = media_type else # I'd rather not have a default content-type, but if none is set then the HTTP adapter sets this to # application/x-www-form-urlencoded and issues a warning about it. headers['Content-Type'] = FALLBACK_CONTENT_TYPE end end if self.headers headers.update(self.headers) end ur = nil faraday_connection(-> (yur) { ur = yur }).run_request(http_method, url, body, headers) ur.scorpio_request = self ur end
if there is only one parameter with the given name, of any sort, this will set it.
@param name [String, Symbol] the 'name' property of one applicable parameter @param value [Object] the applicable parameter will be applied to the request with the given value. @return [Object] echoes the value param @raise [Scorpio::AmbiguousParameter] if more than one parameter has the given name
# File lib/scorpio/request.rb, line 236 def set_param(name, value) param = param_for!(name) set_param_from(param['in'], param['name'], value) value end
@param in [String, Symbol] one of 'path', 'query', 'header', or 'cookie' - where to apply the named value @param name [String, Symbol] the parameter name to apply the value to @param value [Object] the value @return [Object] echoes the value param @raise [ArgumentError] invalid 'in' parameter @raise [NotImplementedError] cookies aren't implemented
# File lib/scorpio/request.rb, line 278 def set_param_from(param_in, name, value) param_in = param_in.to_s if param_in.is_a?(Symbol) name = name.to_s if name.is_a?(Symbol) if param_in == 'path' self.path_params = self.path_params.merge(name => value) elsif param_in == 'query' self.query_params = (self.query_params || {}).merge(name => value) elsif param_in == 'header' self.headers = self.headers.merge(name => value) elsif param_in == 'cookie' raise(NotImplementedError, "cookies not implemented: #{name.inspect} => #{value.inspect}") else raise(ArgumentError, "cannot set param from param_in = #{param_in.inspect} (name: #{name.pretty_inspect.chomp}, value: #{value.pretty_inspect.chomp})") end value end
@return [Addressable::URI] the full URL for this request
# File lib/scorpio/request.rb, line 185 def url unless base_url raise(ArgumentError, "no base_url has been specified for request") end # we do not use Addressable::URI#join as the paths should just be concatenated, not resolved. # we use File.join just to deal with consecutive slashes. Addressable::URI.parse(File.join(base_url, path)) end