Class: Scorpio::Request
- Inherits:
-
Object
- Object
- Scorpio::Request
- Includes:
- Configurables
- Defined in:
- lib/scorpio/request.rb
Overview
a Request from a OpenAPI::Operation. Used by OpenAPI::Operation#build_request and related methods.
Defined Under Namespace
Modules: Configurables
Constant Summary collapse
- SUPPORTED_MEDIA_TYPES =
media types for which Scorpio has implemented generating Configurables#body from Configurables#body_object
%w( application/json application/x-www-form-urlencoded ).map(&:freeze).freeze
- FALLBACK_CONTENT_TYPE =
'application/x-www-form-urlencoded'.freeze
- DEFAULT_USER_AGENT =
-"Scorpio/#{Scorpio::VERSION} (https://github.com/notEthan/scorpio) Faraday/#{Faraday::VERSION} Ruby/#{RUBY_VERSION}"
- METHODS_WITH_BODIES =
see also Faraday::Env::MethodsWithBodies
%w(post put patch options).map(&:freeze).freeze
Instance Attribute Summary collapse
Attributes included from Configurables
#accept, #authorization, #base_url, #body, #body_object, #faraday_adapter, #faraday_builder, #headers, #logger, #media_type, #path_params, #query_params, #scheme, #server, #server_variables, #user_agent
Class Method Summary collapse
Instance Method Summary collapse
-
#content_type ⇒ ::Ur::ContentType
Content-Type for this request, taken from request headers if present, or the request Configurables#media_type.
-
#content_type_header ⇒ ::Ur::ContentType
the value of the request Content-Type header.
-
#each_page_ur(next_page:, raise_on_http_error: true) {|Scorpio::Ur| ... } ⇒ Enumerator?
Runs this request, passing the resulting Ur to the given block.
-
#faraday_connection(yield_ur = nil) ⇒ ::Faraday::Connection
builds a Faraday connection with this Request's faraday_builder and faraday_adapter.
-
#get_param(name) ⇒ Object
returns the value of the named parameter on this request.
-
#get_param_from(param_in, name) ⇒ Object
returns the value of the named parameter from the specified
param_inon this request. -
#http_method ⇒ String
the http method for this request.
- #http_method_with_body? ⇒ Boolean
-
#initialize(operation, **configuration, &b) ⇒ Request
constructor
A new instance of Request.
- #openapi_document ⇒ Scorpio::OpenAPI::Document
- #param_for(name) ⇒ #to_hash?
- #param_for!(name) ⇒ #to_hash
-
#path ⇒ Addressable::URI
an Addressable::URI containing only the path to append to the Configurables#base_url for this request.
-
#path_template ⇒ Addressable::Template
the template for the request's path, to be expanded with Configurables#path_params and appended to the request's Configurables#base_url.
- #request_schema(media_type: self.media_type) ⇒ ::JSI::Schema
-
#run(mutable: false) ⇒ Object
runs this request.
-
#run_ur ⇒ Scorpio::Ur
runs this request and returns the full representation of the request that was run and its response.
-
#set_param(name, value) ⇒ Object
if there is only one parameter with the given name, of any sort, this will set it.
-
#set_param_from(param_in, name, value) ⇒ Object
Applies the given value to the appropriate parameter of the request.
-
#url ⇒ Addressable::URI
the full URL for this request.
Methods included from Configurables
Constructor Details
#initialize(operation, **configuration, &b) ⇒ Request
Returns a new instance of Request.
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
# File 'lib/scorpio/request.rb', line 149 def initialize(operation, **configuration, &b) @operation = operation configuration = JSI::Util.stringify_symbol_keys(configuration) configuration.each do |name, value| if Configurables.public_method_defined?(:"#{name}=") public_send(:"#{name}=", value) else param = param_for(name) || raise(ArgumentError, -"unrecognized configuration value passed: #{name.inspect}") set_param_from(param['in'], param['name'], value) end end if block_given? yield self end end |
Instance Attribute Details
#operation ⇒ Scorpio::OpenAPI::Operation (readonly)
167 168 169 |
# File 'lib/scorpio/request.rb', line 167 def operation @operation end |
Class Method Details
.best_media_type(media_types) ⇒ Object
20 21 22 23 24 25 26 |
# File 'lib/scorpio/request.rb', line 20 def self.best_media_type(media_types) if media_types.size == 1 media_types.first else SUPPORTED_MEDIA_TYPES.detect { |mt| media_types.include?(mt) } end end |
Instance Method Details
#content_type ⇒ ::Ur::ContentType
Content-Type for this request, taken from request headers if present, or the request Scorpio::Request::Configurables#media_type.
236 237 238 |
# File 'lib/scorpio/request.rb', line 236 def content_type content_type_header || (media_type ? ::Ur::ContentType.new(media_type) : nil) end |
#content_type_header ⇒ ::Ur::ContentType
the value of the request Content-Type header
226 227 228 229 230 231 |
# File 'lib/scorpio/request.rb', line 226 def content_type_header headers.each do |k, v| return ::Ur::ContentType.new(v) if k =~ /\Acontent[-_]type\z/i end nil end |
#each_page_ur(next_page:, raise_on_http_error: true) {|Scorpio::Ur| ... } ⇒ Enumerator?
Runs this request, passing the resulting Ur to the given block.
The next_page callable is then called with that Ur and results in the next page's Ur, or nil.
This repeats until the next_page call results in nil.
See OpenAPI::Operation#each_link_page for integration with an OpenAPI Operation.
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 |
# File 'lib/scorpio/request.rb', line 410 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 unless page_ur.is_a?(Scorpio::Ur) raise(TypeError, [ -"next_page must result in a #{Scorpio::Ur}", -"this should be the result of #run_ur from a #{OpenAPI::Operation} or #{Request}", ].join("\n")) end page_ur.raise_on_http_error if raise_on_http_error yield page_ur page_ur = next_page.call(page_ur) end nil end |
#faraday_connection(yield_ur = nil) ⇒ ::Faraday::Connection
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.
250 251 252 253 254 255 256 257 258 259 260 |
# File 'lib/scorpio/request.rb', line 250 def faraday_connection(yield_ur = nil) Faraday.new do |faraday_connection| faraday_builder.call(faraday_connection) if faraday_builder 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 |
#get_param(name) ⇒ Object
returns the value of the named parameter on this request
278 279 280 281 |
# File 'lib/scorpio/request.rb', line 278 def get_param(name) param = param_for!(name) get_param_from(param['in'], param['name']) end |
#get_param_from(param_in, name) ⇒ Object
returns the value of the named parameter from the specified param_in on this request
340 341 342 343 344 345 346 347 348 349 350 351 352 353 |
# File 'lib/scorpio/request.rb', line 340 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.casecmp?(name) } value elsif param_in == 'cookie' raise(NotImplementedError, -"cookies not implemented: #{name.inspect}") else raise(OpenAPI::SemanticError, -"cannot get param from param_in = #{param_in.inspect} (name: #{name.pretty_inspect.chomp})") end end |
#http_method ⇒ String
the http method for this request
176 177 178 |
# File 'lib/scorpio/request.rb', line 176 def http_method operation.http_method end |
#http_method_with_body? ⇒ Boolean
181 182 183 |
# File 'lib/scorpio/request.rb', line 181 def http_method_with_body? METHODS_WITH_BODIES.include?(http_method.to_str.downcase) end |
#openapi_document ⇒ Scorpio::OpenAPI::Document
170 171 172 |
# File 'lib/scorpio/request.rb', line 170 def openapi_document operation.openapi_document end |
#param_for(name) ⇒ #to_hash?
286 287 288 289 290 291 292 293 294 295 296 297 298 |
# File 'lib/scorpio/request.rb', line 286 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_for!(name) ⇒ #to_hash
304 305 306 |
# File 'lib/scorpio/request.rb', line 304 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 |
#path ⇒ Addressable::URI
an Addressable::URI containing only the path to append to the Scorpio::Request::Configurables#base_url for this request
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
# File 'lib/scorpio/request.rb', line 194 def path path_params = JSI::Util.stringify_symbol_keys(self.path_params) missing_variables = path_template.variables - path_params.keys if missing_variables.any? raise(ArgumentError, -"missing params: #{missing_variables.inspect}\nfor path: #{operation.path_template_str}\nfor operation: #{operation.human_id}") end empty_variables = path_template.variables.select { |v| path_params[v].to_s.empty? } if empty_variables.any? raise(ArgumentError, -"empty params: #{empty_variables.inspect}\sfor path: #{operation.path_template_str}\nfor operation #{operation.human_id}") end path = path_template.(path_params) if query_params path.query_values = query_params end path.freeze end |
#path_template ⇒ Addressable::Template
the template for the request's path, to be expanded with Scorpio::Request::Configurables#path_params and appended to the request's Scorpio::Request::Configurables#base_url
188 189 190 |
# File 'lib/scorpio/request.rb', line 188 def path_template operation.path_template end |
#request_schema(media_type: self.media_type) ⇒ ::JSI::Schema
241 242 243 |
# File 'lib/scorpio/request.rb', line 241 def request_schema(media_type: self.media_type) operation.request_schema(media_type: media_type) end |
#run(mutable: false) ⇒ Object
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.
393 394 395 396 397 |
# File 'lib/scorpio/request.rb', line 393 def run(mutable: false) ur = run_ur ur.raise_on_http_error ur.response.body_object(mutable: mutable) end |
#run_ur ⇒ Scorpio::Ur
runs this request and returns the full representation of the request that was run and its response.
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 |
# File 'lib/scorpio/request.rb', line 358 def run_ur headers = {} if user_agent headers['User-Agent'] = user_agent end headers['Accept'] = accept if accept headers['Authorization'] = if 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. if METHODS_WITH_BODIES.include?(http_method.to_s) headers['Content-Type'] = FALLBACK_CONTENT_TYPE end end end headers.update(self.headers) body = self.body ur = nil conn = faraday_connection(-> (yur) { ur = yur }) conn.run_request(http_method.downcase.to_sym, url, body, headers) ur.scorpio_request = self ur end |
#set_param(name, value) ⇒ Object
if there is only one parameter with the given name, of any sort, this will set it.
268 269 270 271 272 |
# File 'lib/scorpio/request.rb', line 268 def set_param(name, value) param = param_for!(name) set_param_from(param['in'], param['name'], value) value end |
#set_param_from(param_in, name, value) ⇒ Object
Applies the given value to the appropriate parameter of the request
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 |
# File 'lib/scorpio/request.rb', line 316 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.to_str) 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 |
#url ⇒ Addressable::URI
the full URL for this request
214 215 216 217 218 219 220 221 222 |
# File 'lib/scorpio/request.rb', line 214 def url return @url if instance_variable_defined?(:@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)).freeze end |