openapi_validator 0.2.0 → 0.3.0

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: 0a2e54a665eba19186fb3b7ca15dfe8707cf38ba121ac7f0ebcc956715f9dd87
4
- data.tar.gz: ddea6b70d0f33c09a81c39025621b9075c836e15d1dda0b066485f4602f70af3
3
+ metadata.gz: 7c840922f71d5eb8be437c9a544b50288b807ba6a7b2b1c1a5aecad9c5ff3a37
4
+ data.tar.gz: 14f0d4fc6828f74125cebc2267362ed8ef6b641980af2bbc2e71241169c056f1
5
5
  SHA512:
6
- metadata.gz: 36f5c80aa8a9252c34581de7963df8e318a84c3b5de85910bf5843f7d446b806c428e485b77dedfe2fef82395c84aecb454905e9fa964337bc81b8ce60c890b3
7
- data.tar.gz: 212fba9b212eb55990d91ac0ae739d8cc0745427414eb41a144601124709df80f844b74d3fccdd6e2dd230bc426688542185d4c536ed2c0b175acf085aaacb23
6
+ metadata.gz: 47ae33c7b4d13fa6c5250b6b68a961142be882af3ee349f07b93df7421c6b18592c6fa830ea2cb4302c3409569dd0b054efbeff2026caca9111e8963ab103df4
7
+ data.tar.gz: 91b5141d6b3046e0108c514a1f6e42382d8c0189a00faeaebe68dd1dda5ff5099ebf0370097cab86ce2e5e4f6aa4b3eb40bab1bed516beb3078635182e300038
@@ -6,7 +6,15 @@ module OpenapiValidator
6
6
  class Error < StandardError; end
7
7
 
8
8
  # @see Validator#initialize
9
- def self.call(*attrs)
10
- Validator.new(*attrs)
9
+ def self.call(doc, **params)
10
+ if doc.is_a? String
11
+ parsed_doc = FileLoader.call(doc)
12
+ elsif doc.is_a? Hash
13
+ parsed_doc = doc
14
+ else
15
+ raise ArgumentError, "Please provide parsed OpenAPI doc as Hash or path to file as String. Passed: #{doc.class}"
16
+ end
17
+
18
+ Validator.new(parsed_doc, **params)
11
19
  end
12
20
  end
@@ -0,0 +1,96 @@
1
+ require 'forwardable'
2
+
3
+ module OpenapiValidator
4
+ class PathValidator
5
+ class Error < StandardError; end
6
+
7
+ extend Forwardable
8
+
9
+ def path
10
+ [path_key, method, @schema_code]
11
+ end
12
+
13
+ def fragment
14
+ build_fragment.tap do |array|
15
+ array.define_singleton_method(:split) do |_|
16
+ self
17
+ end
18
+ end
19
+ end
20
+
21
+ def self.call(**params)
22
+ new(**params).call
23
+ end
24
+
25
+ def call
26
+ validate_path_exists
27
+ self
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :api_doc
33
+
34
+ def_delegators :@request, :media_type, :method, :path_key, :code
35
+
36
+ def initialize(request:, api_doc:)
37
+ @request = request
38
+ @api_doc = api_doc
39
+ end
40
+
41
+ def validate_path_exists
42
+ code_schema.dig(media_type) ||
43
+ raise(Error, "OpenAPI documentation does not have a documented response"\
44
+ " for #{media_type} media-type at path #{method.upcase} #{path_key}")
45
+ end
46
+
47
+ def code_schema
48
+ schema = schema_code
49
+ ref_schema(schema) || content_schema(schema)
50
+ end
51
+
52
+ def content_schema(responses)
53
+ responses.dig("content")
54
+ end
55
+
56
+ def ref_schema(responses)
57
+ schema = responses.dig("$ref")
58
+ return unless schema
59
+
60
+ @fragment_path = "#{schema}/#{media_type}/schema"
61
+ api_doc.dig(*schema[2..-1].split("/"), "content")
62
+ end
63
+
64
+ def schema_code
65
+ responses = responses_schema
66
+ if responses.dig(code)
67
+ @schema_code = code
68
+ elsif responses.dig("default")
69
+ @schema_code = "default"
70
+ else
71
+ raise(Error, "OpenAPI documentation does not have a documented response for code #{code}"\
72
+ " at path #{method.upcase} #{path_key}")
73
+ end
74
+
75
+ responses.dig(@schema_code)
76
+ end
77
+
78
+ def responses_schema
79
+ path_schema.dig(method, "responses") ||
80
+ raise(Error, "OpenAPI documentation does not have a documented path for #{method.upcase} #{path_key}")
81
+ end
82
+
83
+ def path_schema
84
+ api_doc.dig("paths", path_key) ||
85
+ raise(Error, "OpenAPI documentation does not have a documented path for #{path_key}")
86
+ end
87
+
88
+ def build_fragment
89
+ if @fragment_path
90
+ @fragment_path.split("/")
91
+ else
92
+ ["#", "paths", path_key, method, "responses", @schema_code, "content", media_type, "schema"]
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,23 @@
1
+ module OpenapiValidator
2
+ class Request
3
+
4
+ attr_reader :path, :method, :code, :media_type
5
+
6
+ def self.call(**params)
7
+ new(**params)
8
+ end
9
+
10
+ def path_key
11
+ path[/(\/[-_\/\{\}\w]*)/]
12
+ end
13
+
14
+ private
15
+
16
+ def initialize(path:, method:, code:, media_type: "application/json")
17
+ @path = path
18
+ @method = method.to_s
19
+ @code = code.to_s
20
+ @media_type = media_type.to_s
21
+ end
22
+ end
23
+ end
@@ -1,81 +1,46 @@
1
+ require 'openapi_validator/path_validator'
2
+
1
3
  module OpenapiValidator
2
4
  class RequestValidator
3
5
 
4
- attr_reader :errors
6
+ attr_reader :errors, :api_doc, :path_validator
5
7
 
6
8
  def valid?
7
9
  errors.empty?
8
10
  end
9
11
 
10
- def self.call(api_doc, **params)
11
- new(api_doc, **params).call
12
+ def self.call(**params)
13
+ new(**params).call
12
14
  end
13
15
 
14
16
  def call
15
- validate_path_exists
17
+ validate_path
16
18
  self
17
19
  end
18
20
 
19
21
  def validate_response(body:, code:)
20
- response_body = body
21
- response_code = code.to_s
22
- if @code != response_code
23
- @errors << "Path #{path} did not respond with expected status code. Expected #{@code} got #{response_code}"
22
+ if request.code != code.to_s
23
+ @errors << "Path #{request.path} did not respond with expected status code. Expected #{request.code} got #{code}"
24
24
  end
25
- @errors += JSON::Validator.fully_validate(api_doc, response_body, fragment: fragment)
25
+ @errors += JSON::Validator.fully_validate(validator.api_doc, body, fragment: path_validator.fragment)
26
+ validator.remove_validated_path(path_validator.path) if @errors.empty?
26
27
  self
27
28
  end
28
29
 
29
30
  private
30
31
 
31
- attr_reader :api_doc, :path, :method, :code, :media_type
32
+ attr_reader :request, :validator
32
33
 
33
- def initialize(api_doc, path:, method:, code:, media_type: "application/json")
34
- @api_doc = api_doc
35
- @path = path
36
- @method = method.to_s
37
- @code = code.to_s
38
- @media_type = media_type.to_s
34
+ def initialize(request:, validator:)
35
+ @validator = validator
36
+ @request = request
39
37
  @errors = []
40
38
  end
41
39
 
42
- def path_key
43
- path[/(\/[-_\/\{\}\w]*)/]
44
- end
45
-
46
- def fragment
47
- ["#", "paths", path_key, method, "responses", code, "content", media_type, "schema"].tap do |array|
48
- array.define_singleton_method(:split) do |_|
49
- self
50
- end
51
- end
52
- end
53
-
54
- def validate_path_exists
55
- path_schema = api_doc.dig("paths", path_key)
56
- unless path_schema
57
- errors << "OpenAPI documentation does not have a documented path for #{path_key}"
58
- return
59
- end
60
-
61
- responses_schema = path_schema.dig(method, "responses")
62
- unless responses_schema
63
- errors << "OpenAPI documentation does not have a documented path for #{method.upcase} #{path_key}"
64
- return
65
- end
66
-
67
- content_schema = responses_schema.dig(code, "content") || responses_schema.dig("default", "content")
68
- unless content_schema
69
- errors << "OpenAPI documentation does not have a documented response for code #{code}"\
70
- " at path #{method.upcase} #{path_key}"
71
- return
72
- end
73
-
74
- response_schema = content_schema.dig(media_type)
75
- unless response_schema
76
- errors << "OpenAPI documentation does not have a documented response for #{media_type}"\
77
- " media-type at path #{method.upcase} #{path_key}"
78
- end
40
+ def validate_path
41
+ @path_validator = PathValidator.call(request: request, api_doc: validator.api_doc)
42
+ rescue PathValidator::Error => e
43
+ @errors << e.message
79
44
  end
80
45
  end
81
46
  end
@@ -1,32 +1,53 @@
1
1
  require "json-schema"
2
2
  require "openapi_validator/file_loader"
3
3
  require "openapi_validator/documentation_validator"
4
+ require "openapi_validator/request"
4
5
  require "openapi_validator/request_validator"
5
6
 
6
7
  module OpenapiValidator
7
8
  class Validator
8
9
 
9
- attr_reader :api_base_path
10
+ attr_reader :api_base_path, :unvalidated_requests, :api_doc
10
11
 
11
12
  # @return [DocumentationValidator] validation result
12
13
  def validate_documentation
13
14
  DocumentationValidator.call(api_doc, additional_schemas: additional_schemas)
14
15
  end
15
16
 
17
+ # @return [Object] RequestValidator
16
18
  def validate_request(**params)
17
- RequestValidator.call(api_doc, **params)
19
+ RequestValidator.call(request: Request.call(**params), validator: self)
20
+ end
21
+
22
+ # @param [Array] request
23
+ def remove_validated_path(request)
24
+ @unvalidated_requests.delete(request)
18
25
  end
19
26
 
20
27
  private
21
28
 
22
- attr_reader :api_doc, :additional_schemas
29
+ attr_reader :additional_schemas
23
30
 
24
- # @param [String] path path to openapi documentation
31
+ # @param [Hash] doc parsed openapi documentation
25
32
  # @param [Array<String>] additional_schemas paths to custom schemas
26
- def initialize(path, additional_schemas: [], api_base_path: "")
27
- @api_doc = FileLoader.call(path)
33
+ def initialize(doc, additional_schemas: [], api_base_path: "")
34
+ @api_doc = doc
28
35
  @api_base_path = api_base_path
29
36
  @additional_schemas = additional_schemas
37
+ @unvalidated_requests = build_unvalidated_requests
38
+ end
39
+
40
+ # @return [Array]
41
+ def build_unvalidated_requests
42
+ requests = []
43
+ api_doc["paths"] && api_doc["paths"].each do |path, methods|
44
+ methods.each do |method, values|
45
+ values["responses"] && values["responses"].each_key do |code|
46
+ requests << [path, method, code]
47
+ end
48
+ end
49
+ end
50
+ requests
30
51
  end
31
52
  end
32
53
  end
@@ -1,3 +1,3 @@
1
1
  module OpenapiValidator
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openapi_validator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Svyatoslav Kryukov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-10 00:00:00.000000000 Z
11
+ date: 2019-04-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json-schema
@@ -81,6 +81,8 @@ files:
81
81
  - lib/openapi_validator/extended_schema.rb
82
82
  - lib/openapi_validator/extended_type_attribute.rb
83
83
  - lib/openapi_validator/file_loader.rb
84
+ - lib/openapi_validator/path_validator.rb
85
+ - lib/openapi_validator/request.rb
84
86
  - lib/openapi_validator/request_validator.rb
85
87
  - lib/openapi_validator/validator.rb
86
88
  - lib/openapi_validator/version.rb