scorpio 0.6.4 → 0.7.0

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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +6 -1
  3. data/CHANGELOG.md +10 -2
  4. data/LICENSE.md +2 -4
  5. data/README.md +81 -67
  6. data/documents/{github.com/OAI/OpenAPI-Specification/blob/oas3-schema/schemas/v3.0 → spec.openapis.org/oas/3.0}/schema.yaml +164 -628
  7. data/documents/spec.openapis.org/oas/3.1/dialect/base.schema.yaml +22 -0
  8. data/documents/spec.openapis.org/oas/3.1/meta/base.schema.yaml +71 -0
  9. data/documents/spec.openapis.org/oas/3.1/schema-base.yaml +21 -0
  10. data/documents/spec.openapis.org/oas/3.1/schema.yaml +980 -0
  11. data/documents/swagger.io/v2/schema.json +1 -1
  12. data/documents/www.googleapis.com/discovery/v1/apis/discovery/v1/rest.yml +44 -4
  13. data/lib/scorpio/google_api_document.rb +121 -193
  14. data/lib/scorpio/openapi/document.rb +63 -31
  15. data/lib/scorpio/openapi/operation.rb +114 -96
  16. data/lib/scorpio/openapi/operations_scope.rb +35 -19
  17. data/lib/scorpio/openapi/reference.rb +88 -23
  18. data/lib/scorpio/openapi/schema_elements/type_nullable.rb +38 -0
  19. data/lib/scorpio/openapi/schema_elements.rb +7 -0
  20. data/lib/scorpio/openapi/server.rb +34 -0
  21. data/lib/scorpio/openapi/tag.rb +19 -3
  22. data/lib/scorpio/openapi/v2/dialect.rb +66 -0
  23. data/lib/scorpio/openapi/v2.rb +124 -0
  24. data/lib/scorpio/openapi/v3_0/dialect.rb +76 -0
  25. data/lib/scorpio/openapi/v3_0.rb +130 -0
  26. data/lib/scorpio/openapi/v3_1.rb +243 -0
  27. data/lib/scorpio/openapi.rb +23 -203
  28. data/lib/scorpio/request.rb +67 -61
  29. data/lib/scorpio/resource_base.rb +57 -49
  30. data/lib/scorpio/response.rb +28 -10
  31. data/lib/scorpio/ur.rb +7 -3
  32. data/lib/scorpio/version.rb +1 -1
  33. data/lib/scorpio.rb +12 -6
  34. data/pages/Request_Configuration.md +69 -0
  35. data/pages/Security.md +50 -0
  36. data/scorpio.gemspec +6 -5
  37. metadata +28 -15
  38. data/documents/www.googleapis.com/discovery/v1/apis/discovery/v1/rest +0 -684
  39. data/lib/scorpio/openapi/v3/server.rb +0 -44
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Scorpio
4
4
  module OpenAPI
5
- class Error < StandardError
5
+ class Error < Scorpio::Error
6
6
  end
7
7
  # an error in the semantics of an openapi document. for example, an Operation with
8
8
  # two body parameters (in v2, not possible in v3) is a SemanticError. an Operation
@@ -18,219 +18,39 @@ module Scorpio
18
18
  autoload :Document, 'scorpio/openapi/document'
19
19
  autoload :Reference, 'scorpio/openapi/reference'
20
20
  autoload :Tag, 'scorpio/openapi/tag'
21
+ autoload(:Tags, 'scorpio/openapi/tag')
22
+ autoload(:Server, 'scorpio/openapi/server')
21
23
  autoload :OperationsScope, 'scorpio/openapi/operations_scope'
22
24
 
23
- module V3
24
- openapi_document_schema = JSI::JSONSchemaDraft04.new_schema(::YAML.load_file(Scorpio.root.join(
25
- 'documents/github.com/OAI/OpenAPI-Specification/blob/oas3-schema/schemas/v3.0/schema.yaml'
26
- )))
27
-
28
- # the schema represented by Scorpio::OpenAPI::V3::Schema will describe schemas itself.
29
- # JSI::Schema#describes_schema! enables this to implement the functionality of schemas.
30
- describe_schema = [
31
- openapi_document_schema.definitions['Schema'],
32
- openapi_document_schema.definitions['SchemaReference'],
33
- # instead of the Schema definition allowing boolean, properties['additionalProperties']
34
- # is a oneOf which allows a Schema, SchemaReference, or boolean.
35
- # instances of the former two already include the schema implementation (per the previous
36
- # describes_schema entries), but the boolean does not.
37
- # including in properties['additionalProperties'] applies to any additionalProperties.
38
- # (including in properties['additionalProperties'].anyOf[2] would extend booleans too, without
39
- # the redundant inclusion that results for Schema and SchemaRef, but redundant inclusion is not
40
- # a problem, and this way also applies when none of the anyOf match due to schema errors.)
41
- openapi_document_schema.definitions['Schema'].properties['additionalProperties'],
42
- ]
43
- describe_schema.each { |s| s.describes_schema!([JSI::Schema::Draft04]) }
44
-
45
- Document = openapi_document_schema.jsi_schema_module
46
-
47
- # naming these is not strictly necessary, but is nice to have.
48
- # generated: `puts Scorpio::OpenAPI::V3::Document.schema.definitions.keys.map { |k| "#{k[0].upcase}#{k[1..-1]} = Document.definitions['#{k}']" }`
49
-
50
-
51
- Reference = Document.definitions['Reference']
52
- SchemaReference = Document.definitions['SchemaReference']
53
- Info = Document.definitions['Info']
54
- Contact = Document.definitions['Contact']
55
- License = Document.definitions['License']
56
- Server = Document.definitions['Server']
57
- ServerVariable = Document.definitions['ServerVariable']
58
- Components = Document.definitions['Components']
59
- Schema = Document.definitions['Schema']
60
- Discriminator = Document.definitions['Discriminator']
61
- XML = Document.definitions['XML']
62
- Response = Document.definitions['Response']
63
- MediaType = Document.definitions['MediaType']
64
- MediaTypeWithExample = Document.definitions['MediaTypeWithExample']
65
- MediaTypeWithExamples = Document.definitions['MediaTypeWithExamples']
66
- Example = Document.definitions['Example']
67
- Header = Document.definitions['Header']
68
- HeaderWithSchema = Document.definitions['HeaderWithSchema']
69
- HeaderWithSchemaWithExample = Document.definitions['HeaderWithSchemaWithExample']
70
- HeaderWithSchemaWithExamples = Document.definitions['HeaderWithSchemaWithExamples']
71
- HeaderWithContent = Document.definitions['HeaderWithContent']
72
- Paths = Document.definitions['Paths']
73
- PathItem = Document.definitions['PathItem']
74
- Operation = Document.definitions['Operation']
75
- Responses = Document.definitions['Responses']
76
- SecurityRequirement = Document.definitions['SecurityRequirement']
77
- Tag = Document.definitions['Tag']
78
- ExternalDocumentation = Document.definitions['ExternalDocumentation']
79
- Parameter = Document.definitions['Parameter']
80
- ParameterWithSchema = Document.definitions['ParameterWithSchema']
81
- ParameterWithSchemaWithExample = Document.definitions['ParameterWithSchemaWithExample']
82
- ParameterWithSchemaWithExampleInPath = Document.definitions['ParameterWithSchemaWithExampleInPath']
83
- ParameterWithSchemaWithExampleInQuery = Document.definitions['ParameterWithSchemaWithExampleInQuery']
84
- ParameterWithSchemaWithExampleInHeader = Document.definitions['ParameterWithSchemaWithExampleInHeader']
85
- ParameterWithSchemaWithExampleInCookie = Document.definitions['ParameterWithSchemaWithExampleInCookie']
86
- ParameterWithSchemaWithExamples = Document.definitions['ParameterWithSchemaWithExamples']
87
- ParameterWithSchemaWithExamplesInPath = Document.definitions['ParameterWithSchemaWithExamplesInPath']
88
- ParameterWithSchemaWithExamplesInQuery = Document.definitions['ParameterWithSchemaWithExamplesInQuery']
89
- ParameterWithSchemaWithExamplesInHeader = Document.definitions['ParameterWithSchemaWithExamplesInHeader']
90
- ParameterWithSchemaWithExamplesInCookie = Document.definitions['ParameterWithSchemaWithExamplesInCookie']
91
- ParameterWithContent = Document.definitions['ParameterWithContent']
92
- ParameterWithContentInPath = Document.definitions['ParameterWithContentInPath']
93
- ParameterWithContentNotInPath = Document.definitions['ParameterWithContentNotInPath']
94
- RequestBody = Document.definitions['RequestBody']
95
- SecurityScheme = Document.definitions['SecurityScheme']
96
- APIKeySecurityScheme = Document.definitions['APIKeySecurityScheme']
97
- HTTPSecurityScheme = Document.definitions['HTTPSecurityScheme']
98
- NonBearerHTTPSecurityScheme = Document.definitions['NonBearerHTTPSecurityScheme']
99
- BearerHTTPSecurityScheme = Document.definitions['BearerHTTPSecurityScheme']
100
- OAuth2SecurityScheme = Document.definitions['OAuth2SecurityScheme']
101
- OpenIdConnectSecurityScheme = Document.definitions['OpenIdConnectSecurityScheme']
102
- OAuthFlows = Document.definitions['OAuthFlows']
103
- ImplicitOAuthFlow = Document.definitions['ImplicitOAuthFlow']
104
- PasswordOAuthFlow = Document.definitions['PasswordOAuthFlow']
105
- ClientCredentialsFlow = Document.definitions['ClientCredentialsFlow']
106
- AuthorizationCodeOAuthFlow = Document.definitions['AuthorizationCodeOAuthFlow']
107
- Link = Document.definitions['Link']
108
- LinkWithOperationRef = Document.definitions['LinkWithOperationRef']
109
- LinkWithOperationId = Document.definitions['LinkWithOperationId']
110
- Callback = Document.definitions['Callback']
111
- Encoding = Document.definitions['Encoding']
112
-
113
- raise(Bug) unless Schema < JSI::Schema
114
- raise(Bug) unless SchemaReference < JSI::Schema
25
+ module Response
115
26
  end
116
- module V2
117
- openapi_document_schema = JSI.new_schema(::JSON.parse(Scorpio.root.join(
118
- 'documents/swagger.io/v2/schema.json'
119
- ).read))
120
-
121
- # the schema represented by Scorpio::OpenAPI::V2::Schema will describe schemas itself.
122
- # JSI::Schema#describes_schema! enables this to implement the functionality of schemas.
123
- describe_schema = [
124
- openapi_document_schema.definitions['schema'],
125
- # comments above on v3's definitions['Schema'].properties['additionalProperties'] apply here too
126
- openapi_document_schema.definitions['schema'].properties['additionalProperties'],
127
- ]
128
- describe_schema.each { |s| s.describes_schema!([JSI::Schema::Draft04]) }
129
-
130
- Document = openapi_document_schema.jsi_schema_module
131
-
132
- # naming these is not strictly necessary, but is nice to have.
133
- # generated: `puts Scorpio::OpenAPI::V2::Document.schema.definitions.keys.map { |k| "#{k[0].upcase}#{k[1..-1]} = Document.definitions['#{k}']" }`
134
-
135
-
136
- Info = Document.definitions['info']
137
- Contact = Document.definitions['contact']
138
- License = Document.definitions['license']
139
- Paths = Document.definitions['paths']
140
- Definitions = Document.definitions['definitions']
141
- ParameterDefinitions = Document.definitions['parameterDefinitions']
142
- ResponseDefinitions = Document.definitions['responseDefinitions']
143
- ExternalDocs = Document.definitions['externalDocs']
144
- Examples = Document.definitions['examples']
145
- MimeType = Document.definitions['mimeType']
146
- Operation = Document.definitions['operation']
147
- PathItem = Document.definitions['pathItem']
148
- Responses = Document.definitions['responses']
149
- ResponseValue = Document.definitions['responseValue']
150
- Response = Document.definitions['response']
151
- Headers = Document.definitions['headers']
152
- Header = Document.definitions['header']
153
- VendorExtension = Document.definitions['vendorExtension']
154
- BodyParameter = Document.definitions['bodyParameter']
155
- HeaderParameterSubSchema = Document.definitions['headerParameterSubSchema']
156
- QueryParameterSubSchema = Document.definitions['queryParameterSubSchema']
157
- FormDataParameterSubSchema = Document.definitions['formDataParameterSubSchema']
158
- PathParameterSubSchema = Document.definitions['pathParameterSubSchema']
159
- NonBodyParameter = Document.definitions['nonBodyParameter']
160
- Parameter = Document.definitions['parameter']
161
- Schema = Document.definitions['schema']
162
- FileSchema = Document.definitions['fileSchema']
163
- PrimitivesItems = Document.definitions['primitivesItems']
164
- Security = Document.definitions['security']
165
- SecurityRequirement = Document.definitions['securityRequirement']
166
- Xml = Document.definitions['xml']
167
- Tag = Document.definitions['tag']
168
- SecurityDefinitions = Document.definitions['securityDefinitions']
169
- BasicAuthenticationSecurity = Document.definitions['basicAuthenticationSecurity']
170
- ApiKeySecurity = Document.definitions['apiKeySecurity']
171
- Oauth2ImplicitSecurity = Document.definitions['oauth2ImplicitSecurity']
172
- Oauth2PasswordSecurity = Document.definitions['oauth2PasswordSecurity']
173
- Oauth2ApplicationSecurity = Document.definitions['oauth2ApplicationSecurity']
174
- Oauth2AccessCodeSecurity = Document.definitions['oauth2AccessCodeSecurity']
175
- Oauth2Scopes = Document.definitions['oauth2Scopes']
176
- MediaTypeList = Document.definitions['mediaTypeList']
177
- ParametersList = Document.definitions['parametersList']
178
- SchemesList = Document.definitions['schemesList']
179
- CollectionFormat = Document.definitions['collectionFormat']
180
- CollectionFormatWithMulti = Document.definitions['collectionFormatWithMulti']
181
- Title = Document.definitions['title']
182
- Description = Document.definitions['description']
183
- Default = Document.definitions['default']
184
- MultipleOf = Document.definitions['multipleOf']
185
- Maximum = Document.definitions['maximum']
186
- ExclusiveMaximum = Document.definitions['exclusiveMaximum']
187
- Minimum = Document.definitions['minimum']
188
- ExclusiveMinimum = Document.definitions['exclusiveMinimum']
189
- MaxLength = Document.definitions['maxLength']
190
- MinLength = Document.definitions['minLength']
191
- Pattern = Document.definitions['pattern']
192
- MaxItems = Document.definitions['maxItems']
193
- MinItems = Document.definitions['minItems']
194
- UniqueItems = Document.definitions['uniqueItems']
195
- Enum = Document.definitions['enum']
196
- JsonReference = Document.definitions['jsonReference']
197
27
 
198
- raise(Bug) unless Schema < JSI::Schema
28
+ module Paths
199
29
  end
200
30
 
201
- # the autoloads for OpenAPI::Operation and OpenAPI::Document are triggered below. these
202
- # should not be triggered until all the classes their files reference are defined (above).
31
+ module PathItem
32
+ end
203
33
 
34
+ module SecurityScheme
35
+ include(Document::Descendent)
204
36
 
205
- module V3
206
- module Operation
207
- include OpenAPI::Operation
208
- end
209
- module Document
210
- include OpenAPI::Document
211
- end
212
- module Reference
213
- include OpenAPI::Reference
37
+ # @return [Enumerable<OpenAPI::Operation>]
38
+ def operations
39
+ openapi_document.operations.select do |op|
40
+ op.security.respond_to?(:to_ary) && op.security.any? { |sr| sr.each_key.include?(propertyName) }
41
+ end
214
42
  end
215
- module Tag
216
- include OpenAPI::Tag
217
- end
218
- require 'scorpio/openapi/v3/server'
219
- end
220
43
 
221
- module V2
222
- module Operation
223
- include OpenAPI::Operation
224
- end
225
- module Document
226
- include OpenAPI::Document
227
- end
228
- module JsonReference
229
- include OpenAPI::Reference
230
- end
231
- module Tag
232
- include OpenAPI::Tag
44
+ def propertyName
45
+ jsi_ptr.tokens.last
233
46
  end
234
47
  end
48
+
49
+ autoload(:V2, 'scorpio/openapi/v2')
50
+ autoload(:V3, 'scorpio/openapi/v3_0')
51
+ autoload(:V3_0, 'scorpio/openapi/v3_0')
52
+ autoload(:V3_1, 'scorpio/openapi/v3_1')
53
+
54
+ autoload(:SchemaElements, 'scorpio/openapi/schema_elements')
235
55
  end
236
56
  end
@@ -1,16 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Scorpio
4
+ # a Request from a {Scorpio::OpenAPI::Operation}.
5
+ # Used by {Scorpio::OpenAPI::Operation#build_request} and related methods.
4
6
  class Request
5
- # media types for which Scorpio has implemented generating / parsing between body
6
- # and body_object (see {Request#body} and {Response#body_object})
7
- SUPPORTED_REQUEST_MEDIA_TYPES = %w(
7
+ # media types for which Scorpio has implemented generating {Request#body} from {Request#body_object}
8
+ SUPPORTED_MEDIA_TYPES = %w(
8
9
  application/json
9
10
  application/x-www-form-urlencoded
10
11
  ).map(&:freeze).freeze
11
12
 
12
13
  FALLBACK_CONTENT_TYPE = 'application/x-www-form-urlencoded'.freeze
13
14
 
15
+ DEFAULT_USER_AGENT = -"Scorpio/#{Scorpio::VERSION} (https://github.com/notEthan/scorpio) Faraday/#{Faraday::VERSION} Ruby/#{RUBY_VERSION}"
16
+
14
17
  # see also Faraday::Env::MethodsWithBodies
15
18
  METHODS_WITH_BODIES = %w(post put patch options).map(&:freeze).freeze
16
19
 
@@ -18,17 +21,10 @@ module Scorpio
18
21
  if media_types.size == 1
19
22
  media_types.first
20
23
  else
21
- SUPPORTED_REQUEST_MEDIA_TYPES.detect { |mt| media_types.include?(mt) }
24
+ SUPPORTED_MEDIA_TYPES.detect { |mt| media_types.include?(mt) }
22
25
  end
23
26
  end
24
27
 
25
- # @param http_method [String]
26
- # @return [Boolean]
27
- def self.method_with_body?(http_method)
28
- raise(ArgumentError) unless http_method.is_a?(String)
29
- METHODS_WITH_BODIES.include?(http_method.downcase)
30
- end
31
-
32
28
  module Configurables
33
29
  attr_writer :path_params
34
30
  def path_params
@@ -66,6 +62,11 @@ module Scorpio
66
62
  operation.base_url(scheme: scheme, server: server, server_variables: server_variables)
67
63
  end
68
64
 
65
+ # overriding url will cause all of path_params, query_params, querystring, scheme, server, server_variables, and base_url to be ignored
66
+ def url=(url)
67
+ @url = JSI::Util.uri(url)
68
+ end
69
+
69
70
  attr_writer :body
70
71
  def body
71
72
  return @body if instance_variable_defined?(:@body)
@@ -75,13 +76,13 @@ module Scorpio
75
76
  elsif content_type && content_type.form_urlencoded?
76
77
  URI.encode_www_form(body_object)
77
78
 
78
- # NOTE: the supported media types above should correspond to Request::SUPPORTED_REQUEST_MEDIA_TYPES
79
+ # NOTE: the supported media types above should correspond to Request::SUPPORTED_MEDIA_TYPES
79
80
 
80
81
  else
81
82
  if body_object.respond_to?(:to_str)
82
83
  body_object
83
84
  else
84
- raise(NotImplementedError, "Scorpio does not know how to generate the request body with content_type = #{content_type.respond_to?(:to_str) ? content_type : content_type.inspect} for operation: #{operation.human_id}. Scorpio supports media types: #{SUPPORTED_REQUEST_MEDIA_TYPES.join(', ')}. body_object was: #{body_object.pretty_inspect.chomp}")
85
+ raise(NotImplementedError, -"Scorpio does not know how to generate the request body with content_type = #{content_type.respond_to?(:to_str) ? content_type : content_type.inspect} for operation: #{operation.human_id}. Scorpio supports media types: #{SUPPORTED_MEDIA_TYPES.join(', ')}. body_object was: #{body_object.pretty_inspect.chomp}")
85
86
  end
86
87
  end
87
88
  else
@@ -109,6 +110,18 @@ module Scorpio
109
110
  operation.user_agent
110
111
  end
111
112
 
113
+ attr_writer(:accept)
114
+ def accept
115
+ return @accept if instance_variable_defined?(:@accept)
116
+ operation.accept
117
+ end
118
+
119
+ attr_writer(:authorization)
120
+ def authorization
121
+ return @authorization if instance_variable_defined?(:@authorization)
122
+ operation.authorization
123
+ end
124
+
112
125
  attr_writer :faraday_builder
113
126
  def faraday_builder
114
127
  return @faraday_builder if instance_variable_defined?(:@faraday_builder)
@@ -129,35 +142,21 @@ module Scorpio
129
142
  end
130
143
  include Configurables
131
144
 
132
- @request_class_by_operation = Hash.new do |h, op|
133
- h[op] = Class.new(Request) do
134
- define_method(:operation) { op }
135
- include(op.request_accessor_module)
136
- end
137
- end
138
-
139
- def self.request_class_by_operation(operation)
140
- @request_class_by_operation[operation]
141
- end
142
-
143
- # @param configuration [#to_hash] a hash keyed with configurable attributes for
144
- # the request - instance methods of Scorpio::Request::Configurables, whose values
145
- # will be assigned for those attributes.
146
- def initialize(configuration = {}, &b)
145
+ # @param configuration [#to_hash] A hash of configurable attributes or
146
+ # parameters for the request - instance methods of
147
+ # {Scorpio::Request::Configurables}, or request parameters defined by the
148
+ # operation.
149
+ def initialize(operation, **configuration, &b)
150
+ @operation = operation
147
151
  configuration = JSI::Util.stringify_symbol_keys(configuration)
148
- params_set = Set.new # the set of params that have been set
149
- # do the Configurables first
150
152
  configuration.each do |name, value|
151
- if Configurables.public_method_defined?("#{name}=")
152
- Configurables.instance_method("#{name}=").bind(self).call(value)
153
- params_set << name
153
+ if Configurables.public_method_defined?(:"#{name}=")
154
+ public_send(:"#{name}=", value)
155
+ else
156
+ param = param_for(name) || raise(ArgumentError, -"unrecognized configuration value passed: #{name.inspect}")
157
+ set_param_from(param['in'], param['name'], value)
154
158
  end
155
159
  end
156
- # then do other top-level params
157
- configuration.reject { |name, _| params_set.include?(name) }.each do |name, value|
158
- param = param_for(name) || raise(ArgumentError, "unrecognized configuration value passed: #{name.inspect}")
159
- set_param_from(param['in'], param['name'], value)
160
- end
161
160
 
162
161
  if block_given?
163
162
  yield self
@@ -165,7 +164,7 @@ module Scorpio
165
164
  end
166
165
 
167
166
  # @return [Scorpio::OpenAPI::Operation]
168
- attr_reader :operation
167
+ attr_reader(:operation)
169
168
 
170
169
  # @return [Scorpio::OpenAPI::Document]
171
170
  def openapi_document
@@ -178,6 +177,11 @@ module Scorpio
178
177
  operation.http_method
179
178
  end
180
179
 
180
+ # @return [Boolean]
181
+ def http_method_with_body?
182
+ METHODS_WITH_BODIES.include?(http_method.to_str.downcase)
183
+ end
184
+
181
185
  # the template for the request's path, to be expanded with {Configurables#path_params} and appended to
182
186
  # the request's {Configurables#base_url}
183
187
  # @return [Addressable::Template]
@@ -191,13 +195,11 @@ module Scorpio
191
195
  path_params = JSI::Util.stringify_symbol_keys(self.path_params)
192
196
  missing_variables = path_template.variables - path_params.keys
193
197
  if missing_variables.any?
194
- raise(ArgumentError, "path #{operation.path_template_str} for operation #{operation.human_id} requires path_params " +
195
- "which were missing: #{missing_variables.inspect}")
198
+ raise(ArgumentError, -"missing params: #{missing_variables.inspect}\nfor path: #{operation.path_template_str}\nfor operation: #{operation.human_id}")
196
199
  end
197
200
  empty_variables = path_template.variables.select { |v| path_params[v].to_s.empty? }
198
201
  if empty_variables.any?
199
- raise(ArgumentError, "path #{operation.path_template_str} for operation #{operation.human_id} requires path_params " +
200
- "which were empty: #{empty_variables.inspect}")
202
+ raise(ArgumentError, -"empty params: #{empty_variables.inspect}\sfor path: #{operation.path_template_str}\nfor operation #{operation.human_id}")
201
203
  end
202
204
 
203
205
  path = path_template.expand(path_params)
@@ -210,6 +212,7 @@ module Scorpio
210
212
  # the full URL for this request
211
213
  # @return [Addressable::URI]
212
214
  def url
215
+ return @url if instance_variable_defined?(:@url)
213
216
  unless base_url
214
217
  raise(ArgumentError, "no base_url has been specified for request")
215
218
  end
@@ -242,11 +245,11 @@ module Scorpio
242
245
  # builds a Faraday connection with this Request's faraday_builder and faraday_adapter.
243
246
  # passes a given proc yield_ur to middleware to yield an Ur for requests made with the connection.
244
247
  #
245
- # @param yield_ur [Proc]
248
+ # @param yield_ur [Proc, nil]
246
249
  # @return [::Faraday::Connection]
247
250
  def faraday_connection(yield_ur = nil)
248
251
  Faraday.new do |faraday_connection|
249
- faraday_builder.call(faraday_connection)
252
+ faraday_builder.call(faraday_connection) if faraday_builder
250
253
  if yield_ur
251
254
  -> { ::Ur::Faraday }.() # autoload trigger
252
255
 
@@ -289,7 +292,7 @@ module Scorpio
289
292
  nil
290
293
  else
291
294
  raise(AmbiguousParameter.new(
292
- "There are multiple parameters for #{name}. matched parameters were: #{params.pretty_inspect.chomp}"
295
+ -"There are multiple parameters for #{name}. matched parameters were: #{params.pretty_inspect.chomp}"
293
296
  ).tap { |e| e.name = name })
294
297
  end
295
298
  end
@@ -299,15 +302,15 @@ module Scorpio
299
302
  # @raise [Scorpio::ParameterError] if no parameter has the given name
300
303
  # @raise (see #param_for)
301
304
  def param_for!(name)
302
- param_for(name) || raise(ParameterError, "There is no parameter named #{name} on operation #{operation.human_id}:\n#{operation.pretty_inspect.chomp}")
305
+ param_for(name) || raise(ParameterError, -"There is no parameter named #{name} on operation #{operation.human_id}:\n#{operation.pretty_inspect.chomp}")
303
306
  end
304
307
 
305
- # applies the named value to the appropriate parameter of the request
308
+ # Applies the given value to the appropriate parameter of the request
306
309
  # @param param_in [String, Symbol] one of 'path', 'query', 'header', or 'cookie' - where to apply
307
- # the named value
310
+ # the given value
308
311
  # @param name [String, Symbol] the parameter name to apply the value to
309
- # @param value [Object] the value
310
- # @return [Object] echoes the value param
312
+ # @param value [Object] parameter value
313
+ # @return [Object] the given parameter value
311
314
  # @raise [ArgumentError] invalid `param_in` parameter
312
315
  # @raise [NotImplementedError] cookies aren't implemented
313
316
  def set_param_from(param_in, name, value)
@@ -318,11 +321,11 @@ module Scorpio
318
321
  elsif param_in == 'query'
319
322
  self.query_params = (self.query_params || {}).merge(name => value)
320
323
  elsif param_in == 'header'
321
- self.headers = self.headers.merge(name => value)
324
+ self.headers = self.headers.merge(name => value.to_str)
322
325
  elsif param_in == 'cookie'
323
- raise(NotImplementedError, "cookies not implemented: #{name.inspect} => #{value.inspect}")
326
+ raise(NotImplementedError, -"cookies not implemented: #{name.inspect} => #{value.inspect}")
324
327
  else
325
- raise(ArgumentError, "cannot set param from param_in = #{param_in.inspect} (name: #{name.pretty_inspect.chomp}, value: #{value.pretty_inspect.chomp})")
328
+ raise(ArgumentError, -"cannot set param from param_in = #{param_in.inspect} (name: #{name.pretty_inspect.chomp}, value: #{value.pretty_inspect.chomp})")
326
329
  end
327
330
  value
328
331
  end
@@ -340,12 +343,12 @@ module Scorpio
340
343
  elsif param_in == 'query'
341
344
  query_params ? query_params[name] : nil
342
345
  elsif param_in == 'header'
343
- _, value = headers.detect { |headername, _| headername.downcase == name.downcase }
346
+ _, value = headers.detect { |headername, _| headername.casecmp?(name) }
344
347
  value
345
348
  elsif param_in == 'cookie'
346
- raise(NotImplementedError, "cookies not implemented: #{name.inspect}")
349
+ raise(NotImplementedError, -"cookies not implemented: #{name.inspect}")
347
350
  else
348
- raise(OpenAPI::SemanticError, "cannot get param from param_in = #{param_in.inspect} (name: #{name.pretty_inspect.chomp})")
351
+ raise(OpenAPI::SemanticError, -"cannot get param from param_in = #{param_in.inspect} (name: #{name.pretty_inspect.chomp})")
349
352
  end
350
353
  end
351
354
 
@@ -357,6 +360,8 @@ module Scorpio
357
360
  if user_agent
358
361
  headers['User-Agent'] = user_agent
359
362
  end
363
+ headers['Accept'] = accept if accept
364
+ headers['Authorization'] = authorization if authorization
360
365
  if !content_type_header
361
366
  if media_type
362
367
  headers['Content-Type'] = media_type
@@ -382,12 +387,13 @@ module Scorpio
382
387
  # parsed according to an understood media type, and instantiated with the applicable
383
388
  # response schema if one is specified. see {Scorpio::Response#body_object} for more detail.
384
389
  #
390
+ # @param mutable (see Response#body_object)
385
391
  # @raise [Scorpio::HTTPError] if the request returns a 4xx or 5xx status, the appropriate
386
392
  # error is raised - see {Scorpio::HTTPErrors}
387
- def run
393
+ def run(mutable: false)
388
394
  ur = run_ur
389
395
  ur.raise_on_http_error
390
- ur.response.body_object
396
+ ur.response.body_object(mutable: mutable)
391
397
  end
392
398
 
393
399
  # Runs this request, passing the resulting Ur to the given block.
@@ -407,8 +413,8 @@ module Scorpio
407
413
  while page_ur
408
414
  unless page_ur.is_a?(Scorpio::Ur)
409
415
  raise(TypeError, [
410
- "next_page must result in a #{Scorpio::Ur}",
411
- "this should be the result of #run_ur from a #{OpenAPI::Operation} or #{Request}",
416
+ -"next_page must result in a #{Scorpio::Ur}",
417
+ -"this should be the result of #run_ur from a #{OpenAPI::Operation} or #{Request}",
412
418
  ].join("\n"))
413
419
  end
414
420
  page_ur.raise_on_http_error if raise_on_http_error