openapi_first 2.9.1 → 2.9.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6b40040b17718d7e8f1c98bfbdc1182e0d1bb454ff3e2c6c54424c8acdf40ca0
4
- data.tar.gz: f41d5ab780eb888cdec6edbc9bd7d017368af07148ca65a1c09139c88ce9cad9
3
+ metadata.gz: ef8ea95833884daf36e8a33742ce4a6eddfb9343b67de0b5e787ebc377c0691d
4
+ data.tar.gz: b63916918c1d1116d99c2e071c3e8e752b1cce66cd431dceb5076a3e70688c10
5
5
  SHA512:
6
- metadata.gz: 178a990a3ad830e51f1ef9e2fdc15154722ec21ce7d03d9f9592be04226acc45c357a10a956dec8aeb341daaef95bf24c955004800d22ed53b4460111656aeb3
7
- data.tar.gz: c6784c5566dd25bc9e633793aa63574d5e663c135169542d5d3c7137f6cdec6f50892059a5f20cad5fba17ba353339f4b23cd654820accaaa5450417ade30bb9
6
+ metadata.gz: 3cbf77e0a4a51b213a90458c1181bd29474f378195210cf76466c24ef832195b32e4cbd8aec7ba97ece0bd7d9a97b6022e02b5288600d8879b82401c398d1ddc
7
+ data.tar.gz: 8789c3dadcff66b6cbb831dfae948da5adcbcd2788ff40765f39d4a1a0ba238cef1d7df609b4dd57e8ba71653103e21f9fb6a7e1f0a212e45c02d4f8c5e41e39
data/CHANGELOG.md CHANGED
@@ -2,6 +2,15 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 2.9.3
6
+
7
+ - Fix OpenapiFirst.load when MultiJson is configured to return symbol keys
8
+
9
+ ## 2.9.2
10
+
11
+ - OpenapiFirst::Test reports all non-covered requests now
12
+ - Response validation: Improve content type mismatch exception message
13
+
5
14
  ## 2.9.1
6
15
 
7
16
  - Fix OpenapiFirst::Test's request validation to not always raise an error, but only for unknown requests
data/README.md CHANGED
@@ -56,11 +56,7 @@ Here is how to set it up:
56
56
  end
57
57
  ```
58
58
  2. Observe your application. You can do this in one of two ways:
59
- - Inject a Module to wrap (prepend) the `call` method of your Rack app Class.
60
- ```ruby
61
- OpenapiFirst::Test.observe(MyApplication)
62
- ```
63
- - Or add an `app` method to your tests, which wraps your application with silent request / response validation. (✷1)
59
+ - Add an `app` method to your tests, which wraps your application with silent request / response validation. (✷1)
64
60
  ```ruby
65
61
  RSpec.configure do |config|
66
62
  config.include OpenapiFirst::Test::Methods[MyApp], type: :request
@@ -73,6 +69,13 @@ Here is how to set it up:
73
69
  OpenapiFirst::Test.app(MyApp)
74
70
  end
75
71
  ```
72
+ - Or inject a Module to wrap (prepend) the `call` method of your Rack app Class.
73
+
74
+ NOTE: This is still work in progress. It works with basic Sinatra apps, but does not work with Hanami or Rails out of the box, yet. PRs welcome 🤗
75
+
76
+ ```ruby
77
+ OpenapiFirst::Test.observe(MyApplication)
78
+ ```
76
79
  3. Run your tests. The Coverage feature will tell you about missing or invalid requests/responses.
77
80
 
78
81
  (✷1): It does not matter what method of openapi_first you use to validate requests/responses. Instead of using `OpenapiFirstTest.app` to wrap your application, you could also use the [middlewares](#rack-middlewares) or [test assertion method](#test-assertions), but you would have to do that for all requests/responses defined in your API description to make coverage work.
@@ -368,6 +371,8 @@ use OpenapiFirst::Middlewares::RequestValidation, oad
368
371
 
369
372
  ## Development
370
373
 
374
+ Run `git submodule update --init` to initialize the git submodules.
375
+
371
376
  Run `bin/setup` to install dependencies.
372
377
 
373
378
  See `bundle exec rake` to run the linter and the tests.
@@ -13,7 +13,7 @@ module OpenapiFirst
13
13
 
14
14
  body = File.read(file_path)
15
15
  extname = File.extname(file_path)
16
- return JSON.parse(body) if extname == '.json'
16
+ return ::JSON.parse(body) if extname == '.json'
17
17
  return YAML.unsafe_load(body) if ['.yaml', '.yml'].include?(extname)
18
18
 
19
19
  body
@@ -16,20 +16,24 @@ module OpenapiFirst
16
16
  return Match.new(error: Failure.new(:response_not_found, message:), response: nil)
17
17
  end
18
18
  response = FindContent.call(contents, content_type)
19
- if response.nil?
20
- message = "#{content_error(content_type, request_method:,
21
- path:)} Content-Type should be #{contents.keys.join(' or ')}."
22
- return Match.new(error: Failure.new(:response_not_found, message:), response: nil)
23
- end
19
+ return response_not_found(content_type:, contents:, request_method:, path:) unless response
24
20
 
25
21
  Match.new(response:, error: nil)
26
22
  end
27
23
 
28
- def self.content_error(content_type, request_method:, path:)
29
- return 'Response Content-Type must not be empty.' if content_type.nil? || content_type.empty?
30
-
31
- "Response Content-Type #{content_type} is not defined for #{request_method} #{path}."
24
+ def self.response_not_found(content_type:, contents:, request_method:, path:)
25
+ empty_content = content_type.nil? || content_type.empty?
26
+ message =
27
+ "Content-Type should be #{contents.keys.join(' or ')}, " \
28
+ "but was #{empty_content ? 'empty' : content_type} for " \
29
+ "#{request_method.upcase} #{path}"
30
+
31
+ Match.new(
32
+ error: Failure.new(:response_not_found, message:),
33
+ response: nil
34
+ )
32
35
  end
36
+ private_class_method :response_not_found
33
37
 
34
38
  def self.find_status(responses, status)
35
39
  # According to OAS status has to be a string,
@@ -33,14 +33,17 @@ module OpenapiFirst
33
33
  @out.print(string)
34
34
  end
35
35
 
36
- def format_plan(plan)
36
+ def format_plan(plan) # rubocop:disable Metrics/PerceivedComplexity
37
37
  puts ['', "API validation coverage for #{plan.api_identifier}: #{plan.coverage}%"]
38
38
  return if plan.done? && !verbose
39
39
 
40
+ requested_routes_count = plan.routes.count { |route| route.requests.any?(&:requested?) }
41
+ focused_route = requested_routes_count <= 1 && focused
42
+
40
43
  plan.routes.each do |route|
41
44
  next if route.finished? && !verbose
42
45
 
43
- next if route.requests.none?(&:requested?) && focused
46
+ next if route.requests.none?(&:requested?) && focused_route
44
47
 
45
48
  format_requests(route.requests)
46
49
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OpenapiFirst
4
- VERSION = '2.9.1'
4
+ VERSION = '2.9.3'
5
5
  end
data/lib/openapi_first.rb CHANGED
@@ -66,7 +66,7 @@ module OpenapiFirst
66
66
  # @return [Definition]
67
67
  # TODO: This needs to work with unresolved contents as well
68
68
  def self.parse(contents, only: nil, filepath: nil, &)
69
- contents = JSON.parse(JSON.generate(contents)) # Deeply stringify keys, because of YAML. See https://github.com/ahx/openapi_first/issues/367
69
+ contents = ::JSON.parse(::JSON.generate(contents)) # Deeply stringify keys, because of YAML. See https://github.com/ahx/openapi_first/issues/367
70
70
  contents['paths'].filter!(&->(key, _) { only.call(key) }) if only
71
71
  Definition.new(contents, filepath, &)
72
72
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openapi_first
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.9.1
4
+ version: 2.9.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andreas Haller