openapi_contracts 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +41 -20
- data/lib/openapi_contracts/doc/operation.rb +27 -0
- data/lib/openapi_contracts/doc/parameter.rb +22 -59
- data/lib/openapi_contracts/doc/path.rb +23 -38
- data/lib/openapi_contracts/doc/pointer.rb +81 -0
- data/lib/openapi_contracts/doc/request.rb +17 -0
- data/lib/openapi_contracts/doc/response.rb +5 -5
- data/lib/openapi_contracts/doc/schema.rb +44 -10
- data/lib/openapi_contracts/doc/with_parameters.rb +9 -0
- data/lib/openapi_contracts/doc.rb +17 -20
- data/lib/openapi_contracts/match.rb +34 -10
- data/lib/openapi_contracts/operation_router.rb +33 -0
- data/lib/openapi_contracts/parser/transformers/base.rb +15 -0
- data/lib/openapi_contracts/parser/transformers/nullable.rb +10 -0
- data/lib/openapi_contracts/parser/transformers/pointer.rb +34 -0
- data/lib/openapi_contracts/parser/transformers.rb +5 -0
- data/lib/openapi_contracts/parser.rb +61 -0
- data/lib/openapi_contracts/payload_parser.rb +39 -0
- data/lib/openapi_contracts/rspec.rb +2 -2
- data/lib/openapi_contracts/validators/base.rb +5 -1
- data/lib/openapi_contracts/validators/documented.rb +12 -5
- data/lib/openapi_contracts/validators/headers.rb +4 -0
- data/lib/openapi_contracts/validators/http_status.rb +2 -6
- data/lib/openapi_contracts/validators/request_body.rb +26 -0
- data/lib/openapi_contracts/validators/response_body.rb +28 -0
- data/lib/openapi_contracts/validators/schema_validation.rb +40 -0
- data/lib/openapi_contracts/validators.rb +9 -6
- data/lib/openapi_contracts.rb +10 -5
- metadata +30 -20
- data/lib/openapi_contracts/doc/file_parser.rb +0 -85
- data/lib/openapi_contracts/doc/method.rb +0 -18
- data/lib/openapi_contracts/doc/parser.rb +0 -44
- data/lib/openapi_contracts/validators/body.rb +0 -38
@@ -1,11 +1,18 @@
|
|
1
1
|
module OpenapiContracts
|
2
2
|
class Match
|
3
|
+
DEFAULT_OPTIONS = {request_body: false}.freeze
|
4
|
+
MIN_REQUEST_ANCESTORS = %w(Rack::Request::Env Rack::Request::Helpers).freeze
|
5
|
+
MIN_RESPONSE_ANCESTORS = %w(Rack::Response::Helpers).freeze
|
6
|
+
|
3
7
|
attr_reader :errors
|
4
8
|
|
5
9
|
def initialize(doc, response, options = {})
|
6
10
|
@doc = doc
|
7
11
|
@response = response
|
8
|
-
@
|
12
|
+
@request = options.delete(:request) { response.request }
|
13
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
14
|
+
raise ArgumentError, "#{@response} must be compatible with Rack::Response::Helpers" unless response_compatible?
|
15
|
+
raise ArgumentError, "#{@request} must be compatible with Rack::Request::{Env,Helpers}" unless request_compatible?
|
9
16
|
end
|
10
17
|
|
11
18
|
def valid?
|
@@ -17,18 +24,35 @@ module OpenapiContracts
|
|
17
24
|
|
18
25
|
private
|
19
26
|
|
20
|
-
def
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
@
|
27
|
+
def matchers
|
28
|
+
env = Env.new(
|
29
|
+
options: @options,
|
30
|
+
operation: operation,
|
31
|
+
request: @request,
|
32
|
+
response: @response
|
25
33
|
)
|
34
|
+
validators = Validators::ALL.dup
|
35
|
+
validators.delete(Validators::HttpStatus) unless @options[:status]
|
36
|
+
validators.delete(Validators::RequestBody) unless @options[:request_body]
|
37
|
+
validators.reverse
|
38
|
+
.reduce(->(err) { err }) { |s, m| m.new(s, env) }
|
26
39
|
end
|
27
40
|
|
28
|
-
def
|
29
|
-
|
30
|
-
|
31
|
-
|
41
|
+
def operation
|
42
|
+
@doc.operation_for(
|
43
|
+
@options.fetch(:path, @request.path),
|
44
|
+
@request.request_method.downcase
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
def request_compatible?
|
49
|
+
ancestors = @request.class.ancestors.map(&:to_s)
|
50
|
+
MIN_REQUEST_ANCESTORS.all? { |s| ancestors.include?(s) }
|
51
|
+
end
|
52
|
+
|
53
|
+
def response_compatible?
|
54
|
+
ancestors = @response.class.ancestors.map(&:to_s)
|
55
|
+
MIN_RESPONSE_ANCESTORS.all? { |s| ancestors.include?(s) }
|
32
56
|
end
|
33
57
|
end
|
34
58
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module OpenapiContracts
|
2
|
+
class OperationRouter
|
3
|
+
def initialize(doc)
|
4
|
+
@doc = doc
|
5
|
+
@dynamic_paths = doc.paths.select(&:dynamic?)
|
6
|
+
end
|
7
|
+
|
8
|
+
def route(actual_path, method)
|
9
|
+
@doc.with_path(actual_path)&.then { |p| return p.with_method(method) }
|
10
|
+
|
11
|
+
@dynamic_paths.each do |path|
|
12
|
+
next unless path.supports_method?(method)
|
13
|
+
next unless m = path.path_regexp.match(actual_path)
|
14
|
+
|
15
|
+
operation = path.with_method(method)
|
16
|
+
parameters = (path.parameters + operation.parameters).select(&:in_path?)
|
17
|
+
|
18
|
+
return operation if parameter_match?(m.named_captures, parameters)
|
19
|
+
end
|
20
|
+
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def parameter_match?(actual_params, parameters)
|
27
|
+
actual_params.each do |k, v|
|
28
|
+
return false unless parameters&.find { |s| s.name == k }&.matches?(v)
|
29
|
+
end
|
30
|
+
true
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module OpenapiContracts::Parser::Transformers
|
2
|
+
class Pointer < Base
|
3
|
+
def call(object)
|
4
|
+
return unless object['$ref'].present?
|
5
|
+
|
6
|
+
object['$ref'] = transform_pointer(object['$ref'])
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def transform_pointer(target)
|
12
|
+
if %r{^#/(?<pointer>.*)} =~ target
|
13
|
+
# A JSON Pointer
|
14
|
+
generate_absolute_pointer(pointer)
|
15
|
+
elsif %r{^(?<relpath>[^#]+)(?:#/(?<pointer>.*))?} =~ target
|
16
|
+
ptr = @parser.filenesting[@cwd.join(relpath)]
|
17
|
+
tgt = ptr.to_json_pointer
|
18
|
+
tgt += "/#{pointer}" if pointer
|
19
|
+
tgt
|
20
|
+
else
|
21
|
+
target
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# A JSON pointer to the currently parsed file as seen from the root openapi file
|
26
|
+
def generate_absolute_pointer(json_pointer)
|
27
|
+
if @pointer.empty?
|
28
|
+
"#/#{json_pointer}"
|
29
|
+
else
|
30
|
+
"#{@pointer.to_json_pointer}/#{json_pointer}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module OpenapiContracts
|
2
|
+
class Parser
|
3
|
+
autoload :Transformers, 'openapi_contracts/parser/transformers'
|
4
|
+
|
5
|
+
TRANSFORMERS = [Transformers::Nullable, Transformers::Pointer].freeze
|
6
|
+
|
7
|
+
def self.call(dir, filename)
|
8
|
+
new(dir.join(filename)).parse
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :filenesting, :rootfile
|
12
|
+
|
13
|
+
def initialize(rootfile)
|
14
|
+
@cwd = rootfile.parent
|
15
|
+
@rootfile = rootfile
|
16
|
+
@filenesting = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def parse
|
20
|
+
@filenesting = build_file_list
|
21
|
+
@filenesting.each_with_object({}) do |(path, pointer), schema|
|
22
|
+
target = pointer.to_a.reduce(schema) { |d, k| d[k] ||= {} }
|
23
|
+
target.delete('$ref') # ref file pointers must be replaced
|
24
|
+
target.merge! file_to_data(path, pointer)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def build_file_list
|
31
|
+
list = {@rootfile.relative_path_from(@cwd) => Doc::Pointer[]}
|
32
|
+
Dir[File.expand_path('components/**/*.yaml', @cwd)].each do |file|
|
33
|
+
pathname = Pathname(file).relative_path_from(@cwd)
|
34
|
+
pointer = Doc::Pointer.from_path pathname.sub_ext('')
|
35
|
+
list.merge! pathname => pointer
|
36
|
+
end
|
37
|
+
YAML.safe_load_file(@rootfile).fetch('paths') { {} }.each_pair do |k, v|
|
38
|
+
next unless v['$ref'] && !v['$ref'].start_with?('#')
|
39
|
+
|
40
|
+
list.merge! Pathname(v['$ref']) => Doc::Pointer['paths', k]
|
41
|
+
end
|
42
|
+
list
|
43
|
+
end
|
44
|
+
|
45
|
+
def file_to_data(pathname, pointer)
|
46
|
+
YAML.safe_load_file(@cwd.join(pathname)).tap do |data|
|
47
|
+
transform_objects!(data, pathname.parent, pointer)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def transform_objects!(object, cwd, pointer)
|
52
|
+
case object
|
53
|
+
when Hash
|
54
|
+
object.each_value { |v| transform_objects!(v, cwd, pointer) }
|
55
|
+
TRANSFORMERS.map { |t| t.new(self, cwd, pointer) }.each { |t| t.call(object) }
|
56
|
+
when Array
|
57
|
+
object.each { |o| transform_objects!(o, cwd, pointer) }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module OpenapiContracts
|
4
|
+
class PayloadParser
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
class << self
|
8
|
+
delegate :parse, :register, to: :instance
|
9
|
+
end
|
10
|
+
|
11
|
+
Entry = Struct.new(:matcher, :parser) do
|
12
|
+
def call(raw)
|
13
|
+
parser.call(raw)
|
14
|
+
end
|
15
|
+
|
16
|
+
def match?(media_type)
|
17
|
+
matcher == media_type || matcher.match?(media_type)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
@parsers = []
|
23
|
+
end
|
24
|
+
|
25
|
+
def parse(media_type, payload)
|
26
|
+
parser = @parsers.find { |e| e.match?(media_type) }
|
27
|
+
raise ArgumentError, "#{media_type.inspect} is not supported yet" unless parser
|
28
|
+
|
29
|
+
parser.call(payload)
|
30
|
+
end
|
31
|
+
|
32
|
+
def register(matcher, parser)
|
33
|
+
@parsers << Entry.new(matcher, parser)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
PayloadParser.register(%r{(/|\+)json$}, ->(raw) { JSON(raw) })
|
38
|
+
PayloadParser.register('application/x-www-form-urlencoded', ->(raw) { Rack::Utils.parse_nested_query(raw) })
|
39
|
+
end
|
@@ -14,12 +14,12 @@ RSpec::Matchers.define :match_openapi_doc do |doc, options = {}| # rubocop:disab
|
|
14
14
|
end
|
15
15
|
|
16
16
|
description do
|
17
|
-
desc = '
|
17
|
+
desc = 'match the openapi schema'
|
18
18
|
desc << " with #{http_status_desc(@status)}" if @status
|
19
19
|
desc
|
20
20
|
end
|
21
21
|
|
22
|
-
failure_message do |
|
22
|
+
failure_message do |_response|
|
23
23
|
@errors.map { |e| "* #{e}" }.join("\n")
|
24
24
|
end
|
25
25
|
|
@@ -22,7 +22,11 @@ module OpenapiContracts::Validators
|
|
22
22
|
|
23
23
|
private
|
24
24
|
|
25
|
-
delegate :
|
25
|
+
delegate :operation, :options, :request, :response, to: :@env
|
26
|
+
|
27
|
+
def response_desc
|
28
|
+
"#{request.request_method} #{request.path}"
|
29
|
+
end
|
26
30
|
|
27
31
|
# :nocov:
|
28
32
|
def validate
|
@@ -1,18 +1,25 @@
|
|
1
1
|
module OpenapiContracts::Validators
|
2
|
+
# Purpose of this validator
|
3
|
+
# * ensure the operation is documented (combination http-method + path)
|
4
|
+
# * ensure the response-status is documented on the operation
|
2
5
|
class Documented < Base
|
3
6
|
self.final = true
|
4
7
|
|
5
8
|
private
|
6
9
|
|
7
10
|
def validate
|
8
|
-
return
|
11
|
+
return operation_missing unless operation
|
9
12
|
|
10
|
-
|
11
|
-
|
13
|
+
response_missing unless operation.response_for_status(response.status)
|
14
|
+
end
|
15
|
+
|
16
|
+
def operation_missing
|
17
|
+
@errors << "Undocumented operation for #{response_desc.inspect}"
|
12
18
|
end
|
13
19
|
|
14
|
-
def
|
15
|
-
|
20
|
+
def response_missing
|
21
|
+
status_desc = http_status_desc(response.status)
|
22
|
+
@errors << "Undocumented response for #{response_desc.inspect} with #{status_desc}"
|
16
23
|
end
|
17
24
|
end
|
18
25
|
end
|
@@ -5,13 +5,9 @@ module OpenapiContracts::Validators
|
|
5
5
|
private
|
6
6
|
|
7
7
|
def validate
|
8
|
-
return if
|
8
|
+
return if options[:status] == response.status
|
9
9
|
|
10
|
-
@errors << "Response has #{http_status_desc}"
|
11
|
-
end
|
12
|
-
|
13
|
-
def http_status_desc
|
14
|
-
"http status #{Rack::Utils::HTTP_STATUS_CODES[response.status]} (#{response.status})"
|
10
|
+
@errors << "Response has #{http_status_desc(response.status)}"
|
15
11
|
end
|
16
12
|
end
|
17
13
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module OpenapiContracts::Validators
|
2
|
+
class RequestBody < Base
|
3
|
+
include SchemaValidation
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
delegate :media_type, to: :request
|
8
|
+
delegate :request_body, to: :operation
|
9
|
+
|
10
|
+
def data_for_validation
|
11
|
+
request.body.rewind
|
12
|
+
raw = request.body.read
|
13
|
+
OpenapiContracts::PayloadParser.parse(media_type, raw)
|
14
|
+
end
|
15
|
+
|
16
|
+
def validate
|
17
|
+
if !request_body
|
18
|
+
@errors << "Undocumented request body for #{response_desc.inspect}"
|
19
|
+
elsif !request_body.supports_media_type?(media_type)
|
20
|
+
@errors << "Undocumented request with media-type #{media_type.inspect}"
|
21
|
+
else
|
22
|
+
@errors += validate_schema(request_body.schema_for(media_type), data_for_validation)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module OpenapiContracts::Validators
|
2
|
+
class ResponseBody < Base
|
3
|
+
include SchemaValidation
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
delegate :media_type, to: :response
|
8
|
+
|
9
|
+
def data_for_validation
|
10
|
+
# ActionDispatch::Response body is a plain string, while Rack::Response returns an array
|
11
|
+
OpenapiContracts::PayloadParser.parse(media_type, Array.wrap(response.body).join)
|
12
|
+
end
|
13
|
+
|
14
|
+
def spec
|
15
|
+
@spec ||= operation.response_for_status(response.status)
|
16
|
+
end
|
17
|
+
|
18
|
+
def validate
|
19
|
+
if spec.no_content?
|
20
|
+
@errors << 'Expected empty response body' if Array.wrap(response.body).any?(&:present?)
|
21
|
+
elsif !spec.supports_media_type?(media_type)
|
22
|
+
@errors << "Undocumented response with content-type #{media_type.inspect}"
|
23
|
+
else
|
24
|
+
@errors += validate_schema(spec.schema_for(media_type), data_for_validation)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module OpenapiContracts::Validators
|
2
|
+
module SchemaValidation
|
3
|
+
module_function
|
4
|
+
|
5
|
+
def build_validation_schema(schema)
|
6
|
+
schema.raw.merge(
|
7
|
+
'$ref' => schema.fragment,
|
8
|
+
'$schema' => schema_draft_version(schema)
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
def error_to_message(error)
|
13
|
+
pointer = " at #{error['data_pointer']}" if error['data_pointer'].present?
|
14
|
+
if error.key?('details')
|
15
|
+
error['details'].to_a.map { |(key, val)|
|
16
|
+
"#{key.humanize}: #{val}#{pointer}"
|
17
|
+
}.to_sentence
|
18
|
+
else
|
19
|
+
"#{error['data'].inspect}#{pointer} does not match the schema"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def schema_draft_version(schema)
|
24
|
+
if schema.openapi_version.blank? || schema.openapi_version < Gem::Version.new('3.1')
|
25
|
+
# Closest compatible version is actually draft 5 but not supported by json-schemer
|
26
|
+
'http://json-schema.org/draft-04/schema#'
|
27
|
+
else
|
28
|
+
# >= 3.1 is actually comptable with 2020-12 but not yet supported by json-schemer
|
29
|
+
'http://json-schema.org/draft-07/schema#'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def validate_schema(schema, data)
|
34
|
+
schemer = JSONSchemer.schema(build_validation_schema(schema))
|
35
|
+
schemer.validate(data).map do |err|
|
36
|
+
error_to_message(err)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -1,16 +1,19 @@
|
|
1
1
|
module OpenapiContracts
|
2
2
|
module Validators
|
3
|
-
autoload :Base,
|
4
|
-
autoload :
|
5
|
-
autoload :
|
6
|
-
autoload :
|
7
|
-
autoload :
|
3
|
+
autoload :Base, 'openapi_contracts/validators/base'
|
4
|
+
autoload :Documented, 'openapi_contracts/validators/documented'
|
5
|
+
autoload :Headers, 'openapi_contracts/validators/headers'
|
6
|
+
autoload :HttpStatus, 'openapi_contracts/validators/http_status'
|
7
|
+
autoload :RequestBody, 'openapi_contracts/validators/request_body'
|
8
|
+
autoload :ResponseBody, 'openapi_contracts/validators/response_body'
|
9
|
+
autoload :SchemaValidation, 'openapi_contracts/validators/schema_validation'
|
8
10
|
|
9
11
|
# Defines order of matching
|
10
12
|
ALL = [
|
11
13
|
Documented,
|
12
14
|
HttpStatus,
|
13
|
-
|
15
|
+
RequestBody,
|
16
|
+
ResponseBody,
|
14
17
|
Headers
|
15
18
|
].freeze
|
16
19
|
end
|
data/lib/openapi_contracts.rb
CHANGED
@@ -4,17 +4,22 @@ require 'active_support/core_ext/hash'
|
|
4
4
|
require 'active_support/core_ext/class'
|
5
5
|
require 'active_support/core_ext/module'
|
6
6
|
require 'active_support/core_ext/string'
|
7
|
+
require 'rubygems/version'
|
7
8
|
|
8
9
|
require 'json_schemer'
|
10
|
+
require 'rack'
|
9
11
|
require 'yaml'
|
10
12
|
|
11
13
|
module OpenapiContracts
|
12
|
-
autoload :Doc,
|
13
|
-
autoload :Helper,
|
14
|
-
autoload :Match,
|
15
|
-
autoload :
|
14
|
+
autoload :Doc, 'openapi_contracts/doc'
|
15
|
+
autoload :Helper, 'openapi_contracts/helper'
|
16
|
+
autoload :Match, 'openapi_contracts/match'
|
17
|
+
autoload :OperationRouter, 'openapi_contracts/operation_router'
|
18
|
+
autoload :Parser, 'openapi_contracts/parser'
|
19
|
+
autoload :PayloadParser, 'openapi_contracts/payload_parser'
|
20
|
+
autoload :Validators, 'openapi_contracts/validators'
|
16
21
|
|
17
|
-
Env = Struct.new(:
|
22
|
+
Env = Struct.new(:operation, :options, :request, :response, keyword_init: true)
|
18
23
|
|
19
24
|
module_function
|
20
25
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: openapi_contracts
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- mkon
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-08-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -36,42 +36,42 @@ dependencies:
|
|
36
36
|
requirements:
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: 0.
|
39
|
+
version: 1.0.3
|
40
40
|
type: :runtime
|
41
41
|
prerelease: false
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
44
|
- - "~>"
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: 0.
|
46
|
+
version: 1.0.3
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
|
-
name:
|
48
|
+
name: rack
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
50
50
|
requirements:
|
51
|
-
- - "
|
51
|
+
- - ">="
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version:
|
54
|
-
type: :
|
53
|
+
version: 2.0.0
|
54
|
+
type: :runtime
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
requirements:
|
58
|
-
- - "
|
58
|
+
- - ">="
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version:
|
60
|
+
version: 2.0.0
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
|
-
name:
|
62
|
+
name: json_spec
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
64
64
|
requirements:
|
65
65
|
- - "~>"
|
66
66
|
- !ruby/object:Gem::Version
|
67
|
-
version:
|
67
|
+
version: 1.1.5
|
68
68
|
type: :development
|
69
69
|
prerelease: false
|
70
70
|
version_requirements: !ruby/object:Gem::Requirement
|
71
71
|
requirements:
|
72
72
|
- - "~>"
|
73
73
|
- !ruby/object:Gem::Version
|
74
|
-
version:
|
74
|
+
version: 1.1.5
|
75
75
|
- !ruby/object:Gem::Dependency
|
76
76
|
name: rspec
|
77
77
|
requirement: !ruby/object:Gem::Requirement
|
@@ -92,14 +92,14 @@ dependencies:
|
|
92
92
|
requirements:
|
93
93
|
- - '='
|
94
94
|
- !ruby/object:Gem::Version
|
95
|
-
version: 1.
|
95
|
+
version: 1.54.1
|
96
96
|
type: :development
|
97
97
|
prerelease: false
|
98
98
|
version_requirements: !ruby/object:Gem::Requirement
|
99
99
|
requirements:
|
100
100
|
- - '='
|
101
101
|
- !ruby/object:Gem::Version
|
102
|
-
version: 1.
|
102
|
+
version: 1.54.1
|
103
103
|
- !ruby/object:Gem::Dependency
|
104
104
|
name: rubocop-rspec
|
105
105
|
requirement: !ruby/object:Gem::Requirement
|
@@ -138,23 +138,33 @@ files:
|
|
138
138
|
- README.md
|
139
139
|
- lib/openapi_contracts.rb
|
140
140
|
- lib/openapi_contracts/doc.rb
|
141
|
-
- lib/openapi_contracts/doc/file_parser.rb
|
142
141
|
- lib/openapi_contracts/doc/header.rb
|
143
|
-
- lib/openapi_contracts/doc/
|
142
|
+
- lib/openapi_contracts/doc/operation.rb
|
144
143
|
- lib/openapi_contracts/doc/parameter.rb
|
145
|
-
- lib/openapi_contracts/doc/parser.rb
|
146
144
|
- lib/openapi_contracts/doc/path.rb
|
145
|
+
- lib/openapi_contracts/doc/pointer.rb
|
146
|
+
- lib/openapi_contracts/doc/request.rb
|
147
147
|
- lib/openapi_contracts/doc/response.rb
|
148
148
|
- lib/openapi_contracts/doc/schema.rb
|
149
|
+
- lib/openapi_contracts/doc/with_parameters.rb
|
149
150
|
- lib/openapi_contracts/helper.rb
|
150
151
|
- lib/openapi_contracts/match.rb
|
152
|
+
- lib/openapi_contracts/operation_router.rb
|
153
|
+
- lib/openapi_contracts/parser.rb
|
154
|
+
- lib/openapi_contracts/parser/transformers.rb
|
155
|
+
- lib/openapi_contracts/parser/transformers/base.rb
|
156
|
+
- lib/openapi_contracts/parser/transformers/nullable.rb
|
157
|
+
- lib/openapi_contracts/parser/transformers/pointer.rb
|
158
|
+
- lib/openapi_contracts/payload_parser.rb
|
151
159
|
- lib/openapi_contracts/rspec.rb
|
152
160
|
- lib/openapi_contracts/validators.rb
|
153
161
|
- lib/openapi_contracts/validators/base.rb
|
154
|
-
- lib/openapi_contracts/validators/body.rb
|
155
162
|
- lib/openapi_contracts/validators/documented.rb
|
156
163
|
- lib/openapi_contracts/validators/headers.rb
|
157
164
|
- lib/openapi_contracts/validators/http_status.rb
|
165
|
+
- lib/openapi_contracts/validators/request_body.rb
|
166
|
+
- lib/openapi_contracts/validators/response_body.rb
|
167
|
+
- lib/openapi_contracts/validators/schema_validation.rb
|
158
168
|
homepage: https://github.com/mkon/openapi_contracts
|
159
169
|
licenses:
|
160
170
|
- MIT
|
@@ -168,7 +178,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
168
178
|
requirements:
|
169
179
|
- - ">="
|
170
180
|
- !ruby/object:Gem::Version
|
171
|
-
version: '
|
181
|
+
version: '3.0'
|
172
182
|
- - "<"
|
173
183
|
- !ruby/object:Gem::Version
|
174
184
|
version: '3.3'
|