openapi_parser 0.9.0 → 0.10.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e01493b04243073a1fec0acaa56db780076e3c30f3a64534da419bd745408b87
4
- data.tar.gz: 1e57cd341560e800018fa82bbc4801910bbdfdf4a580ccbdaaa63fa0fe442d4a
3
+ metadata.gz: 98afa3c7fb754859a594373659d18ebb81483581c948621d0ea050c360da38ec
4
+ data.tar.gz: 9cf7b695875b6ca55a89a3d5e1a288381d39e203c5fbb469beeb7465232ff0a5
5
5
  SHA512:
6
- metadata.gz: 28182a2367a7ff7314f0c8b35c51d321ce7ce6e9238cd72c83bd57e3cb1970bc9000e19b6a725a47b14ed6262befff61dd325106f9a1389bd72ffa7de7230fe2
7
- data.tar.gz: 0c5560de5b4579933d135d0046a3ae4aaa3e701d83779ff8efd0713023ad5f6d6f37b485f41fa9eb3c3ac5b26c1118afe724d2b9787440e1bfd229c6f0d823a9
6
+ metadata.gz: ddc32d47e0072b78f4790a6b6fa031eab103bb4665d5c0cfe4e7ac2ac9b2e04a048a82f4ddefd40fd112221e389cd86568ac67c3ca9db6f46ae4b9f8ece23c8a
7
+ data.tar.gz: bdd2fdeaec224eaecdde6088abc7eb69513a4ab9e2afffbf23a6a21f9e13a640bddaf6bd7fbbaab16dff588c021bc12296aefd01b1efcb28908f33f8b263f9ad
@@ -1,5 +1,9 @@
1
1
  ## Unreleased
2
2
 
3
+ ## 0.10.0 (2020-04-01)
4
+ * Support $ref to objects in other OpenAPI yaml files #66
5
+ * Allow $ref for path item objects #71
6
+
3
7
  ## 0.9.0 (2020-03-22)
4
8
  * Added support for validating UUID formatted strings #67
5
9
 
@@ -1,4 +1,9 @@
1
+ require 'uri'
1
2
  require 'time'
3
+ require 'json'
4
+ require 'psych'
5
+ require 'pathname'
6
+ require 'open-uri'
2
7
 
3
8
  require 'openapi_parser/version'
4
9
  require 'openapi_parser/config'
@@ -13,14 +18,67 @@ require 'openapi_parser/reference_expander'
13
18
 
14
19
  module OpenAPIParser
15
20
  class << self
21
+ # Load schema yaml object. Uri is not set for returned schema.
16
22
  # @return [OpenAPIParser::Schemas::OpenAPI]
17
23
  def parse(schema, config = {})
18
- c = Config.new(config)
19
- root = Schemas::OpenAPI.new(schema, c)
24
+ load_hash(schema, config: Config.new(config), uri: nil, schema_registry: {})
25
+ end
26
+
27
+ # Load schema in specified filepath. If file path is relative, it is resolved using working directory.
28
+ # @return [OpenAPIParser::Schemas::OpenAPI]
29
+ def load(filepath, config = {})
30
+ path = Pathname.new(filepath)
31
+ path = Pathname.getwd + path if path.relative?
32
+ load_uri(URI.join("file:///", path.to_s), config: Config.new(config), schema_registry: {})
33
+ end
20
34
 
21
- OpenAPIParser::ReferenceExpander.expand(root) if c.expand_reference
35
+ # Load schema located by the passed uri. Uri must be absolute.
36
+ # @return [OpenAPIParser::Schemas::OpenAPI]
37
+ def load_uri(uri, config:, schema_registry:)
38
+ # Open-uri doesn't open file scheme uri, so we try to open file path directly
39
+ # File scheme uri which points to a remote file is not supported.
40
+ content = if uri.scheme == 'file'
41
+ open(uri.path, &:read)
42
+ else
43
+ uri.open(&:read)
44
+ end
22
45
 
23
- root
46
+ extension = Pathname.new(uri.path).extname
47
+ load_hash(parse_file(content, extension), config: config, uri: uri, schema_registry: schema_registry)
24
48
  end
49
+
50
+ private
51
+
52
+ def parse_file(content, extension)
53
+ case extension.downcase
54
+ when '.yaml', '.yml'
55
+ parse_yaml(content)
56
+ when '.json'
57
+ parse_json(content)
58
+ else
59
+ # When extension is something we don't know, try to parse as json first. If it fails, parse as yaml
60
+ begin
61
+ parse_json(content)
62
+ rescue JSON::ParserError
63
+ parse_yaml(content)
64
+ end
65
+ end
66
+ end
67
+
68
+ def parse_yaml(content)
69
+ Psych.safe_load(content)
70
+ end
71
+
72
+ def parse_json(content)
73
+ JSON.parse(content)
74
+ end
75
+
76
+ def load_hash(hash, config:, uri:, schema_registry:)
77
+ root = Schemas::OpenAPI.new(hash, config, uri: uri, schema_registry: schema_registry)
78
+
79
+ OpenAPIParser::ReferenceExpander.expand(root) if config.expand_reference
80
+
81
+ root
82
+ end
25
83
  end
26
84
  end
@@ -1,9 +1,13 @@
1
+ require 'uri'
2
+
1
3
  module OpenAPIParser::Findable
2
4
  # @param [String] reference
3
5
  # @return [OpenAPIParser::Findable]
4
6
  def find_object(reference)
5
- return nil unless reference.start_with?(object_reference)
6
7
  return self if object_reference == reference
8
+ remote_reference = !reference.start_with?('#')
9
+ return find_remote_object(reference) if remote_reference
10
+ return nil unless reference.start_with?(object_reference)
7
11
 
8
12
  @find_object_cache = {} unless defined? @find_object_cache
9
13
  if (obj = @find_object_cache[reference])
@@ -30,4 +34,13 @@ module OpenAPIParser::Findable
30
34
 
31
35
  _openapi_all_child_objects.values.each(&:purge_object_cache)
32
36
  end
37
+
38
+ private
39
+
40
+ def find_remote_object(reference)
41
+ reference_uri = URI(reference)
42
+ fragment = reference_uri.fragment
43
+ reference_uri.fragment = nil
44
+ root.load_another_schema(reference_uri)&.find_object("##{fragment}")
45
+ end
33
46
  end
@@ -178,6 +178,17 @@ module OpenAPIParser
178
178
  end
179
179
  end
180
180
 
181
+ class InvalidUUIDFormat < OpenAPIError
182
+ def initialize(value, reference)
183
+ super(reference)
184
+ @value = value
185
+ end
186
+
187
+ def message
188
+ "#{@reference} Value: #{@value} is not conformant with UUID format"
189
+ end
190
+ end
191
+
181
192
  class NotExistStatusCodeDefinition < OpenAPIError
182
193
  def message
183
194
  "#{@reference} status code definition does not exist"
@@ -27,6 +27,9 @@ class OpenAPIParser::SchemaValidator
27
27
  value, err = validate_email_format(value, schema)
28
28
  return [nil, err] if err
29
29
 
30
+ value, err = validate_uuid_format(value, schema)
31
+ return [nil, err] if err
32
+
30
33
  [value, nil]
31
34
  end
32
35
 
@@ -75,5 +78,13 @@ class OpenAPIParser::SchemaValidator
75
78
 
76
79
  return [nil, OpenAPIParser::InvalidEmailFormat.new(value, schema.object_reference)]
77
80
  end
81
+
82
+ def validate_uuid_format(value, schema)
83
+ return [value, nil] unless schema.format == 'uuid'
84
+
85
+ return [value, nil] if value.match(/[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}/)
86
+
87
+ return [nil, OpenAPIParser::InvalidUUIDFormat.new(value, schema.object_reference)]
88
+ end
78
89
  end
79
90
  end
@@ -5,11 +5,16 @@
5
5
 
6
6
  module OpenAPIParser::Schemas
7
7
  class OpenAPI < Base
8
- def initialize(raw_schema, config)
8
+ def initialize(raw_schema, config, uri: nil, schema_registry: {})
9
9
  super('#', nil, self, raw_schema)
10
10
  @find_object_cache = {}
11
11
  @path_item_finder = OpenAPIParser::PathItemFinder.new(paths) if paths # invalid definition
12
12
  @config = config
13
+ @uri = uri
14
+ @schema_registry = schema_registry
15
+
16
+ # schema_registery is shared among schemas, and prevents a schema from being loaded multiple times
17
+ schema_registry[uri] = self if uri
13
18
  end
14
19
 
15
20
  # @!attribute [r] openapi
@@ -28,5 +33,27 @@ module OpenAPIParser::Schemas
28
33
  def request_operation(http_method, request_path)
29
34
  OpenAPIParser::RequestOperation.create(http_method, request_path, @path_item_finder, @config)
30
35
  end
36
+
37
+ # load another schema with shared config and schema_registry
38
+ # @return [OpenAPIParser::Schemas::OpenAPI]
39
+ def load_another_schema(uri)
40
+ resolved_uri = resolve_uri(uri)
41
+ return if resolved_uri.nil?
42
+
43
+ loaded = @schema_registry[resolved_uri]
44
+ return loaded if loaded
45
+
46
+ OpenAPIParser.load_uri(resolved_uri, config: @config, schema_registry: @schema_registry)
47
+ end
48
+
49
+ private
50
+
51
+ def resolve_uri(uri)
52
+ if uri.absolute?
53
+ uri
54
+ else
55
+ @uri&.merge(uri)
56
+ end
57
+ end
31
58
  end
32
59
  end
@@ -2,6 +2,6 @@ module OpenAPIParser::Schemas
2
2
  class Paths < Base
3
3
  # @!attribute [r] path
4
4
  # @return [Hash{String => PathItem, Reference}, nil]
5
- openapi_attr_hash_body_objects 'path', PathItem, reference: false, allow_data_type: false
5
+ openapi_attr_hash_body_objects 'path', PathItem, reference: true, allow_data_type: false
6
6
  end
7
7
  end
@@ -1,3 +1,3 @@
1
1
  module OpenAPIParser
2
- VERSION = '0.9.0'.freeze
2
+ VERSION = '0.10.0'.freeze
3
3
  end
@@ -24,9 +24,9 @@ Gem::Specification.new do |spec|
24
24
 
25
25
  spec.add_development_dependency 'bundler', '>= 1.16'
26
26
  spec.add_development_dependency 'fincop'
27
- spec.add_development_dependency 'pry'
27
+ spec.add_development_dependency 'pry', '~> 0.12.0'
28
28
  spec.add_development_dependency 'pry-byebug'
29
- spec.add_development_dependency 'rake', '~> 10.0'
29
+ spec.add_development_dependency 'rake', '>= 12.3.3'
30
30
  spec.add_development_dependency 'rspec', '~> 3.0'
31
31
  spec.add_development_dependency 'rspec-parameterized'
32
32
  spec.add_development_dependency 'simplecov'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openapi_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ota42y
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-03-22 00:00:00.000000000 Z
11
+ date: 2020-04-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -42,16 +42,16 @@ dependencies:
42
42
  name: pry
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: 0.12.0
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ">="
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '0'
54
+ version: 0.12.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: pry-byebug
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -70,16 +70,16 @@ dependencies:
70
70
  name: rake
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
- version: '10.0'
75
+ version: 12.3.3
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: '10.0'
82
+ version: 12.3.3
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rspec
85
85
  requirement: !ruby/object:Gem::Requirement
@@ -222,7 +222,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
222
222
  - !ruby/object:Gem::Version
223
223
  version: '0'
224
224
  requirements: []
225
- rubygems_version: 3.1.2
225
+ rubygems_version: 3.0.3
226
226
  signing_key:
227
227
  specification_version: 4
228
228
  summary: OpenAPI3 parser