openapi_first 3.4.2 → 4.0.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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +70 -0
  3. data/README.md +95 -42
  4. data/lib/openapi_first/builder.rb +87 -52
  5. data/lib/openapi_first/child_configuration.rb +0 -2
  6. data/lib/openapi_first/configuration.rb +0 -23
  7. data/lib/openapi_first/definition.rb +35 -2
  8. data/lib/openapi_first/failure.rb +5 -1
  9. data/lib/openapi_first/middlewares/request_validation.rb +1 -1
  10. data/lib/openapi_first/middlewares/response_validation.rb +1 -1
  11. data/lib/openapi_first/parameter/converter/array_converter.rb +42 -0
  12. data/lib/openapi_first/parameter/converter/object_converter.rb +60 -0
  13. data/lib/openapi_first/parameter/converter.rb +69 -0
  14. data/lib/openapi_first/parameter/unpackers.rb +132 -0
  15. data/lib/openapi_first/parameter.rb +70 -0
  16. data/lib/openapi_first/parameter_content_parsers.rb +55 -0
  17. data/lib/openapi_first/parameters_parser.rb +23 -0
  18. data/lib/openapi_first/query_string_parser.rb +93 -0
  19. data/lib/openapi_first/ref_resolver.rb +56 -3
  20. data/lib/openapi_first/request.rb +12 -18
  21. data/lib/openapi_first/request_body_parsers.rb +19 -16
  22. data/lib/openapi_first/request_headers.rb +27 -0
  23. data/lib/openapi_first/request_validator.rb +4 -1
  24. data/lib/openapi_first/response_header.rb +9 -0
  25. data/lib/openapi_first/response_parser.rb +3 -10
  26. data/lib/openapi_first/router.rb +27 -12
  27. data/lib/openapi_first/schema/hash.rb +0 -1
  28. data/lib/openapi_first/sinatra.rb +217 -0
  29. data/lib/openapi_first/test/configuration.rb +0 -34
  30. data/lib/openapi_first/test/coverage/html_reporter/context.rb +24 -17
  31. data/lib/openapi_first/test/coverage/html_reporter.css +214 -67
  32. data/lib/openapi_first/test/coverage/html_reporter.html.erb +39 -11
  33. data/lib/openapi_first/test/coverage/html_reporter.rb +11 -1
  34. data/lib/openapi_first/test/coverage/plan.rb +30 -10
  35. data/lib/openapi_first/test/coverage/request_task.rb +7 -2
  36. data/lib/openapi_first/test/coverage/response_task.rb +6 -1
  37. data/lib/openapi_first/test/coverage/route_task.rb +23 -1
  38. data/lib/openapi_first/test/coverage/skipped_summary.rb +22 -0
  39. data/lib/openapi_first/test/coverage/terminal_reporter.rb +23 -11
  40. data/lib/openapi_first/test/coverage.rb +9 -3
  41. data/lib/openapi_first/test.rb +69 -11
  42. data/lib/openapi_first/validators/multipart_request_body.rb +57 -0
  43. data/lib/openapi_first/validators/request_body.rb +20 -7
  44. data/lib/openapi_first/validators/request_parameters.rb +5 -4
  45. data/lib/openapi_first/version.rb +1 -1
  46. metadata +15 -23
  47. data/lib/openapi_first/header.rb +0 -9
@@ -9,10 +9,11 @@ module OpenapiFirst
9
9
  class RequestTask
10
10
  extend Forwardable
11
11
 
12
- def_delegators :@request, :path, :request_method, :content_type
12
+ def_delegators :@request, :key, :path, :request_method, :content_type
13
13
 
14
- def initialize(request_definition)
14
+ def initialize(request_definition, skipped: false)
15
15
  @request = request_definition
16
+ @skipped = skipped
16
17
  @requested = false
17
18
  @last_error_message = nil
18
19
  end
@@ -25,6 +26,10 @@ module OpenapiFirst
25
26
  @last_error_message = validated_request.error.exception_message unless validated_request.valid?
26
27
  end
27
28
 
29
+ def skipped?
30
+ @skipped == true
31
+ end
32
+
28
33
  def requested?
29
34
  @requested == true
30
35
  end
@@ -11,8 +11,9 @@ module OpenapiFirst
11
11
 
12
12
  def_delegators :@response, :status, :content_type, :key
13
13
 
14
- def initialize(response_definition)
14
+ def initialize(response_definition, skipped: false)
15
15
  @response = response_definition
16
+ @skipped = skipped
16
17
  @responded = false
17
18
  @last_error_message = nil
18
19
  end
@@ -25,6 +26,10 @@ module OpenapiFirst
25
26
  @last_error_message = validated_response.error.exception_message unless validated_response.valid?
26
27
  end
27
28
 
29
+ def skipped?
30
+ @skipped == true
31
+ end
32
+
28
33
  def responded?
29
34
  @responded == true
30
35
  end
@@ -4,8 +4,30 @@ module OpenapiFirst
4
4
  module Test
5
5
  module Coverage
6
6
  RouteTask = Data.define(:path, :request_method, :requests, :responses) do
7
+ def skipped?
8
+ requests.all?(&:skipped?)
9
+ end
10
+
11
+ def tracked_requests
12
+ requests.reject(&:skipped?)
13
+ end
14
+
15
+ def tracked_responses
16
+ responses.reject(&:skipped?)
17
+ end
18
+
19
+ def skipped_requests
20
+ requests.select(&:skipped?)
21
+ end
22
+
23
+ def skipped_responses
24
+ responses.select(&:skipped?)
25
+ end
26
+
7
27
  def finished?
8
- requests.all?(&:finished?) && responses.all?(&:finished?)
28
+ return false if skipped?
29
+
30
+ tracked_requests.all?(&:finished?) && tracked_responses.all?(&:finished?)
9
31
  end
10
32
 
11
33
  def summary
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OpenapiFirst
4
+ module Test
5
+ module Coverage
6
+ # Shared reporting of skipped requests and responses for coverage reporters.
7
+ module SkippedSummary
8
+ def log_skipped_summary(coverage_result)
9
+ requests = coverage_result.skipped_requests_count
10
+ responses = coverage_result.skipped_responses_count
11
+ return if requests.zero? && responses.zero?
12
+
13
+ logger.info "API coverage skipped #{requests} request(s) and #{responses} response(s)."
14
+ return if requests.zero?
15
+
16
+ logger.warn "#{requests} request(s) were skipped entirely. " \
17
+ 'These requests are excluded from API coverage and are not contract-tested at all.'
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -5,17 +5,14 @@ module OpenapiFirst
5
5
  module Coverage
6
6
  # Reports coverage to a logger using ANSI-coloured lines.
7
7
  class TerminalReporter
8
+ include SkippedSummary
9
+
8
10
  def initialize(verbose: false, focused: true, logger: Test.logger)
9
11
  @verbose = verbose
10
12
  @focused = focused && !verbose
11
13
  @logger = logger
12
14
  end
13
15
 
14
- def format(coverage_result)
15
- logger.warn 'DEPRECATION WARNING: TerminalReporter#format is deprecated, use #report instead.'
16
- report(coverage_result)
17
- end
18
-
19
16
  def report(coverage_result)
20
17
  coverage = coverage_result.coverage
21
18
  if coverage.zero?
@@ -23,13 +20,14 @@ module OpenapiFirst
23
20
  'Make sure to observe your application using OpenapiFirst::Test.'
24
21
  end
25
22
  coverage_result.plans.each { |plan| format_plan(plan) } if coverage.positive?
23
+ log_skipped_summary(coverage_result)
26
24
  end
27
25
 
28
26
  private attr_reader :out, :verbose, :focused, :logger
29
27
 
30
28
  private
31
29
 
32
- def format_plan(plan) # rubocop:disable Metrics/PerceivedComplexity
30
+ def format_plan(plan)
33
31
  logger.info "API validation coverage for #{plan.api_identifier}: #{plan.coverage}%"
34
32
  return if plan.done? && !verbose
35
33
 
@@ -37,9 +35,7 @@ module OpenapiFirst
37
35
  focused_route = requested_routes_count <= 1 && focused
38
36
 
39
37
  plan.routes.each do |route|
40
- next if route.finished? && !verbose
41
-
42
- next if route.requests.none?(&:requested?) && focused_route
38
+ next unless report_route?(route, focused_route)
43
39
 
44
40
  format_requests(route.requests)
45
41
 
@@ -47,9 +43,19 @@ module OpenapiFirst
47
43
  end
48
44
  end
49
45
 
46
+ def report_route?(route, focused_route)
47
+ return verbose if route.skipped?
48
+ return false if route.finished? && !verbose
49
+ return false if focused_route && route.requests.none?(&:requested?)
50
+
51
+ true
52
+ end
53
+
50
54
  def format_requests(requests)
51
55
  requests.each do |request|
52
- if request.finished?
56
+ if request.skipped?
57
+ log_skipped "⚠ #{request_label(request)} – Skipped!" if verbose
58
+ elsif request.finished?
53
59
  log_success "✓ #{request_label(request)}"
54
60
  else
55
61
  log_error "❌ #{request_label(request)} – #{explain_unfinished_request(request)}"
@@ -59,7 +65,9 @@ module OpenapiFirst
59
65
 
60
66
  def format_responses(responses)
61
67
  responses.each do |response|
62
- if response.finished?
68
+ if response.skipped?
69
+ log_skipped " #{response_label(response)} – Skipped!" if verbose
70
+ elsif response.finished?
63
71
  log_success " ✓ #{response_label(response)}" if verbose
64
72
  else
65
73
  log_error " ❌ #{response_label(response)} – #{explain_unfinished_response(response)}"
@@ -98,6 +106,10 @@ module OpenapiFirst
98
106
  logger.info "\e[32m#{msg}\e[0m"
99
107
  end
100
108
 
109
+ def log_skipped(msg)
110
+ logger.info "\e[33m#{msg}\e[0m"
111
+ end
112
+
101
113
  def log_error(msg)
102
114
  logger.error "\e[31m#{msg}\e[0m"
103
115
  end
@@ -4,6 +4,7 @@ require_relative 'coverage/plan'
4
4
  require_relative 'coverage/tracker'
5
5
  require_relative 'coverage/covered_request'
6
6
  require_relative 'coverage/covered_response'
7
+ require_relative 'coverage/skipped_summary'
7
8
  require 'drb'
8
9
 
9
10
  module OpenapiFirst
@@ -15,10 +16,15 @@ module OpenapiFirst
15
16
  autoload :TerminalReporter, 'openapi_first/test/coverage/terminal_reporter'
16
17
  autoload :HtmlReporter, 'openapi_first/test/coverage/html_reporter'
17
18
 
18
- # @deprecated Use {TerminalReporter} instead.
19
- TerminalFormatter = TerminalReporter
19
+ Result = Data.define(:plans, :coverage) do
20
+ def skipped_requests_count
21
+ plans.sum(&:skipped_requests_count)
22
+ end
20
23
 
21
- Result = Data.define(:plans, :coverage)
24
+ def skipped_responses_count
25
+ plans.sum(&:skipped_responses_count)
26
+ end
27
+ end
22
28
 
23
29
  class << self
24
30
  def start(skip_response: nil, skip_route: nil)
@@ -5,7 +5,64 @@ require_relative 'test/configuration'
5
5
  require_relative 'registry'
6
6
 
7
7
  module OpenapiFirst
8
- # Test integration
8
+ # Test integration for contract testing. Use this to validate requests/responses against a
9
+ # registered OAD while your test suite runs, and tracks which parts of the API
10
+ # description have been exercised.
11
+ #
12
+ # @example Basic setup (e.g. in spec_helper.rb)
13
+ # require 'openapi_first'
14
+ # OpenapiFirst::Test.setup
15
+ #
16
+ # {.setup} prepares coverage tracking and OAD registration. To actually validate the
17
+ # requests/responses that happen during your tests, you also have to observe your
18
+ # application, i.e. wrap it with silent request/response validation. There are three ways
19
+ # to do this:
20
+ #
21
+ # 1. Include {Methods}, which adds an `app` method wrapping your rack app for rack-test.
22
+ # This is the easiest option if you don't already define `app` yourself:
23
+ # RSpec.configure do |config|
24
+ # config.include OpenapiFirst::Test::Methods[MyApp], type: :request
25
+ # end
26
+ # 2. Call {.observe} to inject validation directly into an app class or instance
27
+ # , if you can't rely on rack-test's `app` method:
28
+ # OpenapiFirst::Test.observe(Rails.application)
29
+ # 3. Call {.app} to wrap an app instance yourself, e.g. if you already define your own
30
+ # `app` method and only want to wrap what it returns:
31
+ # def app
32
+ # OpenapiFirst::Test.app(MyApp.new)
33
+ # end
34
+ #
35
+ # @example Configure via the block passed to .setup
36
+ # OpenapiFirst::Test.setup do |test|
37
+ # test.register('openapi/openapi.yaml')
38
+ #
39
+ # # Ignore certain request/response errors instead of raising them
40
+ # test.ignore_request_error do |validated_request|
41
+ # validated_request.path.start_with?('/legacy') && validated_request.unknown?
42
+ # end
43
+ # test.ignore_response_error do |validated_response, rack_request|
44
+ # validated_response.error.type == :response_status_not_found
45
+ # end
46
+ #
47
+ # # Response status codes that are okay to leave uncovered (default: 401, 404, 500)
48
+ # test.ignored_unknown_status << 403
49
+ # test.ignore_unknown_response_status = true # or: ignore all unknown status codes
50
+ #
51
+ # # Don't raise when a request doesn't match the API description at all
52
+ # test.ignore_unknown_requests = true
53
+ #
54
+ # # Exclude parts of the API description from coverage tracking
55
+ # test.skip_response_coverage { |response_definition| response_definition.status == '5XX' }
56
+ # test.skip_coverage { |path, request_method| path == '/internal' && request_method == 'GET' }
57
+ #
58
+ # # Require minimm of 95% coverage of the API description (default: 100)
59
+ # test.minimum_coverage = 95
60
+ #
61
+ # # Report coverage always (default), only warn, or not at all: true / :warn / false
62
+ # test.report_coverage = :warn
63
+ # end
64
+ #
65
+ # See {OpenapiFirst::Test::Configuration} for the full list of options.
9
66
  module Test # rubocop:disable Metrics/ModuleLength
10
67
  autoload :Coverage, 'openapi_first/test/coverage'
11
68
  autoload :Methods, 'openapi_first/test/methods'
@@ -58,7 +115,7 @@ module OpenapiFirst
58
115
  'Please register your API description via ' \
59
116
  "`OpenapiFirst.register('myopenapi.yaml)` or " \
60
117
  'in a block passed to `OpenapiFirst::Test.setup` like this: ' \
61
- "`OpenapiFirst::Test.setup { |test| test.register('myopenapi.yaml') }` " \
118
+ "`OpenapiFirst::Test.setup { |test| test.register('myopenapi.yaml') }` "
62
119
 
63
120
  end
64
121
 
@@ -83,22 +140,23 @@ module OpenapiFirst
83
140
  return unless configuration.report_coverage == true
84
141
 
85
142
  coverage = Coverage.result.coverage
86
- return if coverage >= configuration.minimum_coverage
143
+ minimum_coverage = configuration.minimum_coverage
87
144
 
88
- puts "API Coverage fails with exit 2, because not all described requests and responses have been tested (#{coverage.round(4)}% covered)." # rubocop:disable Layout/LineLength
145
+ if coverage < minimum_coverage
146
+ logger.error "API Coverage fails with exit 2, because not all described requests and responses have been tested (#{coverage.round(4)}% covered)." # rubocop:disable Layout/LineLength
89
147
 
90
- exit 2
148
+ exit 2
149
+ end
150
+
151
+ return unless coverage - minimum_coverage >= 1.0
152
+
153
+ logger.warn "API Coverage (#{coverage.round(4)}%) is higher than the configured minimum_coverage (#{minimum_coverage}%). You should probably increase minimum_coverage to #{coverage.round(4)}." # rubocop:disable Layout/LineLength
91
154
  end
92
155
 
93
156
  # Print the coverage report
94
157
  # @param reporter A reporter class to render the report.
95
- # @param formatter @deprecated Alias for `reporter:`.
96
158
  # @return [IO] An output where to puts the report.
97
- def self.report_coverage(reporter: Coverage::TerminalReporter, formatter: nil, **)
98
- if formatter
99
- warn 'DEPRECATION WARNING: Test.report_coverage(formatter:) is deprecated, use reporter: instead.'
100
- reporter = formatter
101
- end
159
+ def self.report_coverage(reporter: Coverage::TerminalReporter, **)
102
160
  reporter.new(**).report(Coverage.result)
103
161
  end
104
162
 
@@ -0,0 +1,57 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../schema/validation_result'
4
+
5
+ module OpenapiFirst
6
+ module Validators
7
+ class MultipartRequestBody
8
+ FILE_UPLOAD_PLACEHOLDER = String.new('', encoding: Encoding::BINARY).freeze
9
+
10
+ def initialize(content_schema:)
11
+ @schema = content_schema
12
+ end
13
+
14
+ def call(parsed_request)
15
+ body = parsed_request.body
16
+ return if body.nil?
17
+
18
+ uploads = collect_file_uploads(body)
19
+ uploads.each_key { write_at(body, _1, FILE_UPLOAD_PLACEHOLDER) }
20
+ begin
21
+ validate(body)
22
+ ensure
23
+ uploads.each { |path, upload| write_at(body, path, upload) }
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ def validate(body)
30
+ validation = Schema::ValidationResult.new(
31
+ @schema.validate(body, access_mode: 'write')
32
+ )
33
+ Failure.new(:invalid_body, errors: validation.errors) if validation.error?
34
+ end
35
+
36
+ def collect_file_uploads(value, path = [], result = {})
37
+ case value
38
+ when ::Hash
39
+ if value.key?(:tempfile)
40
+ result[path] = value unless path.empty?
41
+ else
42
+ value.each { |key, item| collect_file_uploads(item, path + [key], result) }
43
+ end
44
+ when ::Array
45
+ value.each_with_index { |item, index| collect_file_uploads(item, path + [index], result) }
46
+ end
47
+ result
48
+ end
49
+
50
+ def write_at(root, path, value)
51
+ *parents, key = path
52
+ container = parents.empty? ? root : root.dig(*parents)
53
+ container[key] = value if container
54
+ end
55
+ end
56
+ end
57
+ end
@@ -1,20 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'multipart_request_body'
4
+
3
5
  module OpenapiFirst
4
6
  module Validators
5
7
  class RequestBody
6
- def initialize(content_schema:, required_request_body:)
8
+ MULTIPART = %r{\Amultipart/}i
9
+ private_constant :MULTIPART
10
+
11
+ REQUIREMENT = lambda do |parsed_request|
12
+ Failure.new(:invalid_body, message: 'Request body must not be empty') if parsed_request.body.nil?
13
+ end
14
+ private_constant :REQUIREMENT
15
+
16
+ def self.for(content_schema:, required_request_body:, content_type:)
17
+ validators = []
18
+ validators << REQUIREMENT if required_request_body
19
+ klass = MULTIPART.match?(content_type.to_s) ? MultipartRequestBody : self
20
+ validators << klass.new(content_schema:)
21
+ validators
22
+ end
23
+
24
+ def initialize(content_schema:)
7
25
  @schema = content_schema
8
- @required = required_request_body
9
26
  end
10
27
 
11
28
  def call(parsed_request)
12
29
  body = parsed_request.body
13
- if body.nil?
14
- return Failure.new(:invalid_body, message: 'Request body must not be empty') if @required
15
-
16
- return
17
- end
30
+ return if body.nil?
18
31
 
19
32
  validation = Schema::ValidationResult.new(
20
33
  @schema.validate(body, access_mode: 'write')
@@ -2,8 +2,9 @@
2
2
 
3
3
  module OpenapiFirst
4
4
  module Validators
5
+ # @visibility private
5
6
  module RequestParameters
6
- RequestHeaders = Data.define(:schema) do
7
+ Headers = Data.define(:schema) do
7
8
  def call(parsed_request)
8
9
  validation = schema.validate(parsed_request.headers)
9
10
  Failure.new(:invalid_header, errors: validation.errors) if validation.error?
@@ -24,7 +25,7 @@ module OpenapiFirst
24
25
  end
25
26
  end
26
27
 
27
- RequestCookies = Data.define(:schema) do
28
+ Cookies = Data.define(:schema) do
28
29
  def call(parsed_request)
29
30
  validation = schema.validate(parsed_request.cookies)
30
31
  Failure.new(:invalid_cookie, errors: validation.errors) if validation.error?
@@ -34,8 +35,8 @@ module OpenapiFirst
34
35
  VALIDATORS = {
35
36
  path_schema: Path,
36
37
  query_schema: Query,
37
- header_schema: RequestHeaders,
38
- cookie_schema: RequestCookies
38
+ header_schema: Headers,
39
+ cookie_schema: Cookies
39
40
  }.freeze
40
41
 
41
42
  def self.for(args)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OpenapiFirst
4
- VERSION = '3.4.2'
4
+ VERSION = '4.0.0'
5
5
  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: 3.4.2
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andreas Haller
@@ -57,26 +57,6 @@ dependencies:
57
57
  - - "<"
58
58
  - !ruby/object:Gem::Version
59
59
  version: '3.0'
60
- - !ruby/object:Gem::Dependency
61
- name: openapi_parameters
62
- requirement: !ruby/object:Gem::Requirement
63
- requirements:
64
- - - ">="
65
- - !ruby/object:Gem::Version
66
- version: 0.12.0
67
- - - "<"
68
- - !ruby/object:Gem::Version
69
- version: '2.0'
70
- type: :runtime
71
- prerelease: false
72
- version_requirements: !ruby/object:Gem::Requirement
73
- requirements:
74
- - - ">="
75
- - !ruby/object:Gem::Version
76
- version: 0.12.0
77
- - - "<"
78
- - !ruby/object:Gem::Version
79
- version: '2.0'
80
60
  - !ruby/object:Gem::Dependency
81
61
  name: rack
82
62
  requirement: !ruby/object:Gem::Requirement
@@ -117,20 +97,29 @@ files:
117
97
  - lib/openapi_first/errors.rb
118
98
  - lib/openapi_first/failure.rb
119
99
  - lib/openapi_first/file_loader.rb
120
- - lib/openapi_first/header.rb
121
100
  - lib/openapi_first/json.rb
122
101
  - lib/openapi_first/middlewares/request_validation.rb
123
102
  - lib/openapi_first/middlewares/response_validation.rb
103
+ - lib/openapi_first/parameter.rb
104
+ - lib/openapi_first/parameter/converter.rb
105
+ - lib/openapi_first/parameter/converter/array_converter.rb
106
+ - lib/openapi_first/parameter/converter/object_converter.rb
107
+ - lib/openapi_first/parameter/unpackers.rb
108
+ - lib/openapi_first/parameter_content_parsers.rb
109
+ - lib/openapi_first/parameters_parser.rb
124
110
  - lib/openapi_first/parsed_request.rb
125
111
  - lib/openapi_first/plugins.rb
126
112
  - lib/openapi_first/plugins/x_public.rb
113
+ - lib/openapi_first/query_string_parser.rb
127
114
  - lib/openapi_first/ref_resolver.rb
128
115
  - lib/openapi_first/registry.rb
129
116
  - lib/openapi_first/request.rb
130
117
  - lib/openapi_first/request_body_parsers.rb
118
+ - lib/openapi_first/request_headers.rb
131
119
  - lib/openapi_first/request_validator.rb
132
120
  - lib/openapi_first/response.rb
133
121
  - lib/openapi_first/response_body_parsers.rb
122
+ - lib/openapi_first/response_header.rb
134
123
  - lib/openapi_first/response_parser.rb
135
124
  - lib/openapi_first/response_validator.rb
136
125
  - lib/openapi_first/router.rb
@@ -140,6 +129,7 @@ files:
140
129
  - lib/openapi_first/schema/hash.rb
141
130
  - lib/openapi_first/schema/validation_error.rb
142
131
  - lib/openapi_first/schema/validation_result.rb
132
+ - lib/openapi_first/sinatra.rb
143
133
  - lib/openapi_first/test.rb
144
134
  - lib/openapi_first/test/app.rb
145
135
  - lib/openapi_first/test/callable.rb
@@ -155,6 +145,7 @@ files:
155
145
  - lib/openapi_first/test/coverage/request_task.rb
156
146
  - lib/openapi_first/test/coverage/response_task.rb
157
147
  - lib/openapi_first/test/coverage/route_task.rb
148
+ - lib/openapi_first/test/coverage/skipped_summary.rb
158
149
  - lib/openapi_first/test/coverage/terminal_reporter.rb
159
150
  - lib/openapi_first/test/coverage/tracker.rb
160
151
  - lib/openapi_first/test/logger.rb
@@ -165,6 +156,7 @@ files:
165
156
  - lib/openapi_first/test/plain_helpers.rb
166
157
  - lib/openapi_first/validated_request.rb
167
158
  - lib/openapi_first/validated_response.rb
159
+ - lib/openapi_first/validators/multipart_request_body.rb
168
160
  - lib/openapi_first/validators/request_body.rb
169
161
  - lib/openapi_first/validators/request_parameters.rb
170
162
  - lib/openapi_first/validators/response_body.rb
@@ -193,7 +185,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
193
185
  - !ruby/object:Gem::Version
194
186
  version: '0'
195
187
  requirements: []
196
- rubygems_version: 4.0.10
188
+ rubygems_version: 4.0.16
197
189
  specification_version: 4
198
190
  summary: OpenAPI based request validation, response validation, contract-testing and
199
191
  coverage
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OpenapiFirst
4
- Header = Data.define(:name, :required?, :schema, :node) do
5
- def resolved_schema
6
- node['schema']&.resolved
7
- end
8
- end
9
- end