forked from ota42y/openapi_parser
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathopenapi_parser.rb
118 lines (102 loc) · 4.12 KB
/
openapi_parser.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
require 'uri'
require 'time'
require 'json'
require 'psych'
require 'pathname'
require 'open-uri'
require 'openapi_parser/version'
require 'openapi_parser/config'
require 'openapi_parser/errors'
require 'openapi_parser/concern'
require 'openapi_parser/schemas'
require 'openapi_parser/schemas_3_1'
require 'openapi_parser/path_item_finder'
require 'openapi_parser/request_operation'
require 'openapi_parser/schema_validator'
require 'openapi_parser/parameter_validator'
require 'openapi_parser/reference_expander'
module OpenAPIParser
class << self
# Load schema hash object. Uri is not set for returned schema.
# @return [OpenAPIParser::Schemas::OpenAPI]
def parse(schema, config = {})
load_hash(schema, config: Config.new(config), uri: nil, schema_registry: {})
end
# @param filepath [String] Path of the file containing the passed schema.
# Used for resolving remote $ref if provided.
# If file path is relative, it is resolved using working directory.
# @return [OpenAPIParser::Schemas::OpenAPI]
def parse_with_filepath(schema, filepath, config = {})
load_hash(schema, config: Config.new(config), uri: filepath && file_uri(filepath), schema_registry: {})
end
# Load schema in specified filepath. If file path is relative, it is resolved using working directory.
# @return [OpenAPIParser::Schemas::OpenAPI]
def load(filepath, config = {})
load_uri(file_uri(filepath), config: Config.new(config), schema_registry: {})
end
# Load schema located by the passed uri. Uri must be absolute.
# @return [OpenAPIParser::Schemas::OpenAPI]
def load_uri(uri, config:, schema_registry:)
# Open-uri doesn't open file scheme uri, so we try to open file path directly
# File scheme uri which points to a remote file is not supported.
uri_path = uri.path
raise "file not found" if uri_path.nil?
content = if uri.scheme == 'file'
open(uri_path)&.read
elsif uri.is_a?(OpenURI::OpenRead)
uri.open()&.read
end
extension = Pathname.new(uri_path).extname
load_hash(parse_file(content, extension), config: config, uri: uri, schema_registry: schema_registry)
end
private
def file_uri(filepath)
path = Pathname.new(filepath)
path = Pathname.getwd + path if path.relative?
URI.join("file:///", path.to_s)
end
def parse_file(content, ext)
case ext.downcase
when '.yaml', '.yml'
parse_yaml(content)
when '.json'
parse_json(content)
else
# When extension is something we don't know, try to parse as json first. If it fails, parse as yaml
begin
parse_json(content)
rescue JSON::ParserError
parse_yaml(content)
end
end
end
def parse_yaml(content)
# FIXME: when drop ruby 2.5, we should use permitted_classes
(Gem::Version.create(RUBY_VERSION) < Gem::Version.create("2.6.0")) ?
Psych.safe_load(content, [Date, Time]) :
Psych.safe_load(content, permitted_classes: [Date, Time])
end
def parse_json(content)
raise "json content is nil" unless content
JSON.parse(content)
end
def load_hash(hash, config:, uri:, schema_registry:)
case hash["openapi"]&.split('.')
in ['3', '0', _]
root = Schemas::OpenAPI.new(hash, config, uri: uri, schema_registry: schema_registry)
in ['3', '1', _]
root = Schemas31::OpenAPI.new(hash, config, uri: uri, schema_registry: schema_registry)
else
# Too avoid breaking changes, we don't raise error here.
# raise NotSupportedSpecificationVersionError.new("Unsupported specification version: #{hash['openapi']}")
root = Schemas::OpenAPI.new(hash, config, uri: uri, schema_registry: schema_registry)
end
OpenAPIParser::ReferenceExpander.expand(root, config.strict_reference_validation) if config.expand_reference
# TODO: use callbacks
root.paths&.path&.values&.each do | path_item |
path_item.set_path_item_to_operation
end
root
end
end
end