openapi_validator 0.1.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.
@@ -0,0 +1,12 @@
1
+ require "openapi_validator/extended_schema"
2
+ require "openapi_validator/validator"
3
+ require "openapi_validator/version"
4
+
5
+ module OpenapiValidator
6
+ class Error < StandardError; end
7
+
8
+ # @see Validator#initialize
9
+ def self.call(*attrs)
10
+ Validator.new(*attrs)
11
+ end
12
+ end
@@ -0,0 +1,57 @@
1
+ require "json-schema"
2
+ require "openapi_validator/file_loader"
3
+
4
+ module OpenapiValidator
5
+ class DocumentationValidator
6
+
7
+ attr_reader :errors
8
+
9
+ # @param [Hash] api_doc parsed openapi documentation
10
+ # @param [Array<String>] additional_schemas paths to custom schemas
11
+ # @return [DocumentationValidator] validation result
12
+ def self.call(api_doc, additional_schemas: [])
13
+ new(api_doc, additional_schemas: additional_schemas).call
14
+ end
15
+
16
+ # @return [DocumentationValidator]
17
+ def call
18
+ validate
19
+ end
20
+
21
+ # @return [true, false]
22
+ def valid?
23
+ errors.empty?
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :api_doc, :schemas
29
+
30
+ # @return [DocumentationValidator]
31
+ def validate
32
+ parsed_schemas.each do |schema|
33
+ errors.concat JSON::Validator.fully_validate(schema, api_doc)
34
+ end
35
+
36
+ self
37
+ end
38
+
39
+ # @return [Array<Hash>] parsed custom schemas
40
+ def parsed_schemas
41
+ schemas.map { |schema| FileLoader.call(schema) }
42
+ end
43
+
44
+ # @param [Hash] api_doc parsed openapi documentation
45
+ # @param [Array<String>] additional_schemas paths to custom schemas
46
+ def initialize(api_doc, additional_schemas:)
47
+ @api_doc = api_doc
48
+ @schemas = additional_schemas.unshift openapi_schema
49
+ @errors = []
50
+ end
51
+
52
+ # @return [String] path to openapi v3 schema
53
+ def openapi_schema
54
+ File.expand_path("../../../data/openapi-3.0.json", __FILE__)
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,16 @@
1
+ require "openapi_validator/extended_type_attribute"
2
+ require "json-schema"
3
+
4
+ module OpenapiValidator
5
+ class ExtendedSchema < JSON::Schema::Draft4
6
+ def initialize
7
+ super
8
+ @attributes['type'] = ExtendedTypeAttribute
9
+ @uri = URI.parse('http://tempuri.org/apivore/extended_schema')
10
+ @names = ['http://tempuri.org/apivore/extended_schema']
11
+ end
12
+
13
+ JSON::Validator.register_validator(self.new)
14
+ JSON::Validator.register_default_validator(self.new)
15
+ end
16
+ end
@@ -0,0 +1,10 @@
1
+ require "json-schema/attributes/type_v4"
2
+
3
+ module OpenapiValidator
4
+ class ExtendedTypeAttribute < JSON::Schema::TypeV4Attribute
5
+ def self.validate(current_schema, data, fragments, processor, validator, options = {})
6
+ return if data.nil? && current_schema.schema["nullable"] == true
7
+ super
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,34 @@
1
+ require "json"
2
+ require "yaml"
3
+
4
+ module OpenapiValidator
5
+ class FileLoader
6
+
7
+ # @param [String] path path to file
8
+ # @return [Hash] parsed file
9
+ def self.call(path)
10
+ new(path).call
11
+ end
12
+
13
+ # @return [Hash] parsed file
14
+ def call
15
+ case File.extname(path)
16
+ when ".yml", ".yaml"
17
+ YAML.load_file(path)
18
+ when ".json"
19
+ JSON.parse(File.read(path))
20
+ else
21
+ raise "Can't parse #{path}. It should be json or yaml file.", Error
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :path
28
+
29
+ # @param [String] path path to file
30
+ def initialize(path)
31
+ @path = path
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,77 @@
1
+ module OpenapiValidator
2
+ class RequestValidator
3
+
4
+ attr_reader :errors
5
+
6
+ def valid?
7
+ errors.empty?
8
+ end
9
+
10
+ def self.call(api_doc, **params)
11
+ new(api_doc, **params).call
12
+ end
13
+
14
+ def call
15
+ validate_path_exists
16
+ self
17
+ end
18
+
19
+ def validate_response(response_body)
20
+ @response_body = response_body
21
+ @errors += JSON::Validator.fully_validate(api_doc, response_body, fragment: fragment)
22
+ self
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :api_doc, :path, :method, :code, :media_type
28
+
29
+ def initialize(api_doc, path:, method:, code:, media_type: "application/json")
30
+ @api_doc = api_doc
31
+ @path = path
32
+ @method = method.to_s
33
+ @code = code.to_s
34
+ @media_type = media_type.to_s
35
+ @errors = []
36
+ end
37
+
38
+ def path_key
39
+ path[/(\/[-_\/\{\}\w]*)/]
40
+ end
41
+
42
+ def fragment
43
+ ["#", "paths", path_key, method, "responses", code, "content", media_type, "schema"].tap do |array|
44
+ array.define_singleton_method(:split) do |_|
45
+ self
46
+ end
47
+ end
48
+ end
49
+
50
+ def validate_path_exists
51
+ path_schema = api_doc.dig("paths", path_key)
52
+ unless path_schema
53
+ errors << "OpenAPI documentation does not have a documented path for #{path_key}"
54
+ return
55
+ end
56
+
57
+ responses_schema = path_schema.dig(method, "responses")
58
+ unless responses_schema
59
+ errors << "OpenAPI documentation does not have a documented path for #{method.upcase} #{path_key}"
60
+ return
61
+ end
62
+
63
+ content_schema = responses_schema.dig(code, "content") || responses_schema.dig("default", "content")
64
+ unless content_schema
65
+ errors << "OpenAPI documentation does not have a documented response for code #{code}"\
66
+ " at path #{method.upcase} #{path_key}"
67
+ return
68
+ end
69
+
70
+ response_schema = content_schema.dig(media_type)
71
+ unless response_schema
72
+ errors << "OpenAPI documentation does not have a documented response for #{media_type}"\
73
+ " media-type at path #{method.upcase} #{path_key}"
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,32 @@
1
+ require "json-schema"
2
+ require "openapi_validator/file_loader"
3
+ require "openapi_validator/documentation_validator"
4
+ require "openapi_validator/request_validator"
5
+
6
+ module OpenapiValidator
7
+ class Validator
8
+
9
+ attr_reader :api_base_path
10
+
11
+ # @return [DocumentationValidator] validation result
12
+ def validate_documentation
13
+ DocumentationValidator.call(api_doc, additional_schemas: additional_schemas)
14
+ end
15
+
16
+ def validate_request(**params)
17
+ RequestValidator.call(api_doc, **params)
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :api_doc, :additional_schemas
23
+
24
+ # @param [String] path path to openapi documentation
25
+ # @param [Array<String>] additional_schemas paths to custom schemas
26
+ def initialize(path, additional_schemas: [], api_base_path: "")
27
+ @api_doc = FileLoader.call(path)
28
+ @api_base_path = api_base_path
29
+ @additional_schemas = additional_schemas
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,3 @@
1
+ module OpenapiValidator
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,29 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "openapi_validator/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "openapi_validator"
7
+ spec.version = OpenapiValidator::VERSION
8
+ spec.authors = ["Svyatoslav Kryukov"]
9
+ spec.email = ["s.g.kryukov@yandex.ru"]
10
+
11
+ spec.summary = "Validator used for openapi_rspec"
12
+ spec.homepage = "https://github.com/llcmedsolutions/openapi_validator"
13
+ spec.license = "MIT"
14
+
15
+ # Specify which files should be added to the gem when it is released.
16
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
17
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
18
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_runtime_dependency "json-schema", "~> 2.8"
25
+
26
+ spec.add_development_dependency "bundler", "~> 2.0"
27
+ spec.add_development_dependency "rake", "~> 10.0"
28
+ spec.add_development_dependency "rspec", "~> 3.0"
29
+ end
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: openapi_validator
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Svyatoslav Kryukov
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-04-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: json-schema
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.8'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.8'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description:
70
+ email:
71
+ - s.g.kryukov@yandex.ru
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - ".gitignore"
77
+ - ".rspec"
78
+ - ".travis.yml"
79
+ - Gemfile
80
+ - Gemfile.lock
81
+ - LICENSE.txt
82
+ - README.md
83
+ - Rakefile
84
+ - bin/console
85
+ - bin/setup
86
+ - data/openapi-3.0.json
87
+ - lib/openapi_validator.rb
88
+ - lib/openapi_validator/documentation_validator.rb
89
+ - lib/openapi_validator/extended_schema.rb
90
+ - lib/openapi_validator/extended_type_attribute.rb
91
+ - lib/openapi_validator/file_loader.rb
92
+ - lib/openapi_validator/request_validator.rb
93
+ - lib/openapi_validator/validator.rb
94
+ - lib/openapi_validator/version.rb
95
+ - openapi_validator.gemspec
96
+ homepage: https://github.com/llcmedsolutions/openapi_validator
97
+ licenses:
98
+ - MIT
99
+ metadata: {}
100
+ post_install_message:
101
+ rdoc_options: []
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ requirements:
106
+ - - ">="
107
+ - !ruby/object:Gem::Version
108
+ version: '0'
109
+ required_rubygems_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ requirements: []
115
+ rubygems_version: 3.0.1
116
+ signing_key:
117
+ specification_version: 4
118
+ summary: Validator used for openapi_rspec
119
+ test_files: []