openapi_first 2.0.2 → 2.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 87fceda33e397fa75a8268144e5cbacfb802333a5ef1c315676d14458312b01b
4
- data.tar.gz: a734ee73e2dce89fea8d2fc93c713b0505923b2b2098b560a2b44ef3e5753c84
3
+ metadata.gz: a500abac816ab74de8b74c3d72793f31865d8c0c4863b7af769d748b99a85790
4
+ data.tar.gz: cf0394ab100eea73f66ff5275ff81bc1fb7cb06d63ed69f62cb961db48966f61
5
5
  SHA512:
6
- metadata.gz: 63d51c543d3d689ced06170e1e53f6d0a20056af2643e1f1fccfbf966b14352c55ad9c0dfd92478ceb7e5aaac0b6f7c7563e17d9e69ab2f924f6a9d4846c45ff
7
- data.tar.gz: 8649d5737439a2414802e17ed562a0efdf294f29e7515b0e248e5736cd59235eba876baf52aad8e5d602ff90ba5afc8902ed1609d902dfe03c65d4136afc1042
6
+ metadata.gz: eb03e7141b82b6ae39d59948e5a3ce90a67c8ec2744b257ca18ed95cf537796200923e4bbc1bccfca5a2359995405f5015df29a01947e0add2ec653dfa44b778
7
+ data.tar.gz: 16458594f9cfef02f7faa3bd207487d74c8eaf400704c1631d80edca3ab1ae6d5820213c8efb85145be3f1dc3a1f91020cfb5b7c9330bd52c6acfca601fc7eb5
data/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 2.0.4
6
+
7
+ - Fix issue with parsing reponse body when using Rails https://github.com/ahx/openapi_first/issues/281
8
+
9
+ ## 2.0.3
10
+
11
+ - Fix `OpenapiFirst::Test.register` https://github.com/ahx/openapi_first/issues/276
12
+
13
+ - Request validation middleware now accepts `error_response: false` do disable rendering a response. This is useful if you just want to collect metrics (via hooks) during a migration phase.
14
+
5
15
  ## 2.0.2
6
16
 
7
17
  - Fix setting custom error response (thanks @gobijan)
data/README.md CHANGED
@@ -2,17 +2,20 @@
2
2
 
3
3
  OpenapiFirst helps to implement HTTP APIs based on an [OpenAPI](https://www.openapis.org/) API description. It supports OpenAPI 3.0 and 3.1. It offers request and response validation and it ensures that your implementation follows exactly the API description.
4
4
 
5
+ [![Tests](https://github.com/ahx/openapi_first/actions/workflows/ruby.yml/badge.svg)](https://github.com/ahx/openapi_first/actions/workflows/ruby.yml)
6
+ [![CodeQL](https://github.com/ahx/openapi_first/actions/workflows/codeql.yml/badge.svg)](https://github.com/ahx/openapi_first/blob/codeql/.github/workflows/codeql.yml)
7
+
5
8
  ## Contents
6
9
 
7
10
  <!-- TOC -->
8
11
 
12
+ - [Manual use](#manual-use)
13
+ - [Validate request](#validate-request)
14
+ - [Validate response](#validate-response)
9
15
  - [Rack Middlewares](#rack-middlewares)
10
16
  - [Request validation](#request-validation)
11
17
  - [Response validation](#response-validation)
12
18
  - [Test assertions](#test-assertions)
13
- - [Manual use](#manual-use)
14
- - [Validate request](#validate-request)
15
- - [Validate response](#validate-response)
16
19
  - [Framework integration](#framework-integration)
17
20
  - [Configuration](#configuration)
18
21
  - [Hooks](#hooks)
@@ -23,6 +26,61 @@ OpenapiFirst helps to implement HTTP APIs based on an [OpenAPI](https://www.open
23
26
 
24
27
  <!-- /TOC -->
25
28
 
29
+ ## Manual use
30
+
31
+ Load the API description:
32
+
33
+ ```ruby
34
+ require 'openapi_first'
35
+
36
+ definition = OpenapiFirst.load('openapi.yaml')
37
+ ```
38
+
39
+ ### Validate request
40
+
41
+ ```ruby
42
+ validated_request = definition.validate_request(rack_request)
43
+
44
+ # Inspect the request and access parsed parameters
45
+ validated_request.valid?
46
+ validated_request.invalid?
47
+ validated_request.error # => Failure object or nil
48
+ validated_request.parsed_body # => The parsed request body (Hash)
49
+ validated_request.parsed_query # A Hash of query parameters that are defined in the API description, parsed exactly as described.
50
+ validated_request.parsed_path_parameters
51
+ validated_request.parsed_headers
52
+ validated_request.parsed_cookies
53
+ validated_request.parsed_params # Merged parsed path, query parameters and request body
54
+ # Access the Openapi 3 Operation Object Hash
55
+ validated_request.operation['x-foo']
56
+ validated_request.operation['operationId'] => "getStuff"
57
+ # or the whole request definition
58
+ validated_request.request_definition.path # => "/pets/{petId}"
59
+ validated_request.request_definition.operation_id # => "showPetById"
60
+
61
+ # Or you can raise an exception if validation fails:
62
+ definition.validate_request(rack_request, raise_error: true) # Raises OpenapiFirst::RequestInvalidError or OpenapiFirst::NotFoundError if request is invalid
63
+ ```
64
+
65
+ ### Validate response
66
+
67
+ ```ruby
68
+ validated_response = definition.validate_response(rack_request, rack_response)
69
+
70
+ # Inspect the response and access parsed parameters and
71
+ validated_response.valid?
72
+ validated_response.invalid?
73
+ validated_response.error # => Failure object or nil
74
+ validated_response.status # => 200
75
+ validated_response.parsed_body
76
+ validated_response.parsed_headers
77
+
78
+ # Or you can raise an exception if validation fails:
79
+ definition.validate_response(rack_request,rack_response, raise_error: true) # Raises OpenapiFirst::ResponseInvalidError or OpenapiFirst::ResponseNotFoundError
80
+ ```
81
+
82
+ OpenapiFirst uses [`multi_json`](https://rubygems.org/gems/multi_json).
83
+
26
84
  ## Rack Middlewares
27
85
 
28
86
  ### Request validation
@@ -39,7 +97,7 @@ use OpenapiFirst::Middlewares::RequestValidation, spec: 'openapi.yaml'
39
97
  | :---------------- | ------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- |
40
98
  | `spec:` | | The path to the spec file or spec loaded via `OpenapiFirst.load` |
41
99
  | `raise_error:` | `false` (default), `true` | If set to true the middleware raises `OpenapiFirst::RequestInvalidError` or `OpenapiFirst::NotFoundError` instead of returning 4xx. |
42
- | `error_response:` | `:default` (default), `:jsonapi`, Your implementation of `ErrorResponse` |
100
+ | `error_response:` | `:default` (default), `:jsonapi`, Your implementation of `ErrorResponse` or `false` to disable responding |
43
101
 
44
102
  #### Error responses
45
103
 
@@ -174,67 +232,6 @@ class TripsApiTest < ActionDispatch::IntegrationTest
174
232
  end
175
233
  ```
176
234
 
177
- ## Manual use
178
-
179
- Load the API description:
180
-
181
- ```ruby
182
- require 'openapi_first'
183
-
184
- definition = OpenapiFirst.load('openapi.yaml')
185
- ```
186
-
187
- ### Validate request
188
-
189
- ```ruby
190
- # Find and validate request
191
- rack_request = Rack::Request.new(env)
192
- validated_request = definition.validate_request(rack_request)
193
- # Or raise an exception if validation fails:
194
- definition.validate_request(rack_request, raise_error: true) # Raises OpenapiFirst::RequestInvalidError or OpenapiFirst::NotFoundError if request is invalid
195
-
196
- # Inspect the request and access parsed parameters
197
- validated_request.known? # Is the request defined in the API description?
198
- validated_request.valid? # => true / false
199
- validated_request.invalid? # => true / false
200
- validated_request.error # => Failure object if request is invalid
201
- validated_request.parsed_params # Merged parsed path, query parameters and request body
202
- validated_request.parsed_body
203
- validated_request.parsed_path_parameters # => { "pet_id" => 42 }
204
- validated_request.parsed_headers
205
- validated_request.parsed_cookies
206
- validated_request.parsed_query
207
-
208
- # Access the Openapi 3 Operation Object Hash
209
- validated_request.operation['x-foo']
210
- validated_request.operation['operationId']
211
- # or the whole request definition
212
- validated_request.request_definition.path # => "/pets/{petId}"
213
- validated_request.request_definition.operation_id # => "showPetById"
214
- ```
215
-
216
- ### Validate response
217
-
218
- ```ruby
219
- # Find and validate the response
220
- rack_response = Rack::Response[*app.call(env)]
221
- validated_response = definition.validate_response(rack_request, rack_response)
222
-
223
- # Raise an exception if validation fails:
224
- definition.validate_response(rack_request,rack_response, raise_error: true) # Raises OpenapiFirst::ResponseInvalidError or OpenapiFirst::ResponseNotFoundError
225
-
226
- # Inspect the response and access parsed parameters and
227
- response.known? # Is the response defined in the API description?
228
- response.valid? # => true / false
229
- response.invalid? # => true / false
230
- response.error # => Failure object if response is invalid
231
- response.status # => 200
232
- response.parsed_body
233
- response.parsed_headers
234
- ```
235
-
236
- OpenapiFirst uses [`multi_json`](https://rubygems.org/gems/multi_json).
237
-
238
235
  ## Configuration
239
236
 
240
237
  You can configure default options globally:
@@ -10,11 +10,13 @@ module OpenapiFirst
10
10
  # :raise_error A Boolean indicating whether to raise an error if validation fails.
11
11
  # default: false
12
12
  # :error_response The Class to use for error responses.
13
+ # This can be a Symbol-name of an registered error response (:default, :jsonapi)
14
+ # or it can be set to false to disable returning a response.
13
15
  # default: OpenapiFirst::Plugins::Default::ErrorResponse (Config.default_options.error_response)
14
16
  def initialize(app, options = {})
15
17
  @app = app
16
18
  @raise = options.fetch(:raise_error, OpenapiFirst.configuration.request_validation_raise_error)
17
- @error_response_class = error_response(options[:error_response])
19
+ @error_response_class = error_response_option(options[:error_response])
18
20
 
19
21
  spec = options.fetch(:spec)
20
22
  raise "You have to pass spec: when initializing #{self.class}" unless spec
@@ -29,17 +31,18 @@ module OpenapiFirst
29
31
  validated = @definition.validate_request(Rack::Request.new(env), raise_error: @raise)
30
32
  env[REQUEST] = validated
31
33
  failure = validated.error
32
- return @error_response_class.new(failure:).render if failure
34
+ return @error_response_class.new(failure:).render if failure && @error_response_class
33
35
 
34
36
  @app.call(env)
35
37
  end
36
38
 
37
39
  private
38
40
 
39
- def error_response(mod)
40
- return OpenapiFirst.find_error_response(mod) if mod.is_a?(Symbol)
41
+ def error_response_option(value)
42
+ return if value == false
43
+ return OpenapiFirst.find_error_response(value) if value.is_a?(Symbol)
41
44
 
42
- mod || OpenapiFirst.configuration.request_validation_error_response
45
+ value || OpenapiFirst.configuration.request_validation_error_response
43
46
  end
44
47
  end
45
48
  end
@@ -25,20 +25,9 @@ module OpenapiFirst
25
25
 
26
26
  def call(env)
27
27
  status, headers, body = @app.call(env)
28
- body = read_body(body)
29
28
  @definition.validate_response(Rack::Request.new(env), Rack::Response[status, headers, body], raise_error: @raise)
30
29
  [status, headers, body]
31
30
  end
32
-
33
- private
34
-
35
- def read_body(body)
36
- return body.to_ary if body.respond_to?(:to_ary)
37
-
38
- result = []
39
- body.each { |part| result << part }
40
- result
41
- end
42
31
  end
43
32
  end
44
33
  end
@@ -5,8 +5,8 @@ module OpenapiFirst
5
5
  # @visibility private
6
6
  class PathTemplate
7
7
  # See also https://spec.openapis.org/oas/v3.1.0#path-templating
8
- TEMPLATE_EXPRESSION = /(\{[^}]+\})/
9
- TEMPLATE_EXPRESSION_NAME = /\{([^}]+)\}/
8
+ TEMPLATE_EXPRESSION = /(\{[^{}]+\})/
9
+ TEMPLATE_EXPRESSION_NAME = /\{([^{}]+)\}/
10
10
  ALLOWED_PARAMETER_CHARACTERS = %r{([^/?#]+)}
11
11
 
12
12
  def self.template?(string)
@@ -7,7 +7,8 @@ module OpenapiFirst
7
7
  module Test
8
8
  class NotRegisteredError < StandardError; end
9
9
 
10
- DEFINITIONS = {}.freeze
10
+ DEFINITIONS = {} # rubocop:disable Style/MutableConstant
11
+
11
12
  def self.definitions = DEFINITIONS
12
13
 
13
14
  def self.register(path, as: :default)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OpenapiFirst
4
- VERSION = '2.0.2'
4
+ VERSION = '2.0.4'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openapi_first
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andreas Haller
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-06-26 00:00:00.000000000 Z
11
+ date: 2024-07-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hana