openapi3_parser 0.1.0 → 0.2.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 +4 -4
- data/.gitignore +3 -0
- data/CHANGELOG.md +6 -0
- data/README.md +5 -1
- data/TODO.md +1 -0
- data/lib/openapi3_parser.rb +13 -0
- data/lib/openapi3_parser/context.rb +2 -2
- data/lib/openapi3_parser/node_factories/array.rb +4 -2
- data/lib/openapi3_parser/node_factories/components.rb +4 -0
- data/lib/openapi3_parser/node_factories/schema.rb +15 -2
- data/lib/openapi3_parser/node_factories/server_variable.rb +10 -2
- data/lib/openapi3_parser/node_factory.rb +17 -1
- data/lib/openapi3_parser/node_factory/map.rb +4 -0
- data/lib/openapi3_parser/node_factory/object.rb +3 -5
- data/lib/openapi3_parser/node_factory/object/node_builder.rb +19 -8
- data/lib/openapi3_parser/nodes/array.rb +8 -0
- data/lib/openapi3_parser/nodes/callback.rb +1 -0
- data/lib/openapi3_parser/nodes/components.rb +12 -0
- data/lib/openapi3_parser/nodes/contact.rb +4 -0
- data/lib/openapi3_parser/nodes/discriminator.rb +3 -0
- data/lib/openapi3_parser/nodes/encoding.rb +6 -0
- data/lib/openapi3_parser/nodes/example.rb +5 -0
- data/lib/openapi3_parser/nodes/external_documentation.rb +3 -0
- data/lib/openapi3_parser/nodes/header.rb +1 -0
- data/lib/openapi3_parser/nodes/info.rb +7 -0
- data/lib/openapi3_parser/nodes/license.rb +3 -0
- data/lib/openapi3_parser/nodes/link.rb +7 -0
- data/lib/openapi3_parser/nodes/map.rb +6 -0
- data/lib/openapi3_parser/nodes/media_type.rb +5 -0
- data/lib/openapi3_parser/nodes/oauth_flow.rb +5 -0
- data/lib/openapi3_parser/nodes/oauth_flows.rb +5 -0
- data/lib/openapi3_parser/nodes/openapi.rb +11 -0
- data/lib/openapi3_parser/nodes/operation.rb +16 -0
- data/lib/openapi3_parser/nodes/parameter.rb +3 -0
- data/lib/openapi3_parser/nodes/parameter/parameter_like.rb +14 -0
- data/lib/openapi3_parser/nodes/path_item.rb +14 -0
- data/lib/openapi3_parser/nodes/paths.rb +1 -0
- data/lib/openapi3_parser/nodes/request_body.rb +4 -0
- data/lib/openapi3_parser/nodes/response.rb +5 -0
- data/lib/openapi3_parser/nodes/responses.rb +2 -0
- data/lib/openapi3_parser/nodes/schema.rb +38 -0
- data/lib/openapi3_parser/nodes/security_requirement.rb +1 -0
- data/lib/openapi3_parser/nodes/security_scheme.rb +9 -0
- data/lib/openapi3_parser/nodes/server.rb +5 -2
- data/lib/openapi3_parser/nodes/server_variable.rb +4 -0
- data/lib/openapi3_parser/nodes/tag.rb +4 -0
- data/lib/openapi3_parser/nodes/xml.rb +8 -2
- data/lib/openapi3_parser/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f60ae34f39675f7ce3616bd96dc3e383275d117d
|
4
|
+
data.tar.gz: 4ecf6bffd69c875778c4d096f29cf7b5deadbf7e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f5a96679f760117e345c9e992161444c06df7d667953fad6badf547dd83dee449b672cc9f265a26a7166e2cdec887d5205bf0dcda6abdbece2a2ce74aeb61153
|
7
|
+
data.tar.gz: 087aea7ab5f4abceb69b9acce6854f70dac44fca1620bde695d7dd1a7813ca1a468728e3cc5a08ab5ae31d5320c75459f9537ce584c6ffbff082ca796d9a3602
|
data/.gitignore
CHANGED
data/CHANGELOG.md
ADDED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# OpenAPI 3 Parser
|
2
2
|
|
3
|
-
[](https://travis-ci.org/kevindew/openapi3_parser)
|
4
4
|
|
5
5
|
|
6
6
|
This is a parser/validator for [Open API 3][openapi-3] built in Ruby.
|
@@ -19,7 +19,11 @@ document.valid?
|
|
19
19
|
document.paths["/"]
|
20
20
|
```
|
21
21
|
|
22
|
+
Documentation for the API to navigate the OpenAPI nodes is available on
|
23
|
+
[rubydoc.info][docs].
|
24
|
+
|
22
25
|
[openapi-3]: https://github.com/OAI/OpenAPI-Specification
|
26
|
+
[docs]: http://www.rubydoc.info/github/kevindew/openapi3_parser/Openapi3Parser/Nodes/Openapi
|
23
27
|
|
24
28
|
## Status
|
25
29
|
|
data/TODO.md
CHANGED
@@ -28,3 +28,4 @@ These are the steps defined to reach 1.0. Assistance is very welcome.
|
|
28
28
|
- [ ] Improve the modelling of namespace
|
29
29
|
- [ ] Set up nicer string representations of key classes to help them be
|
30
30
|
debugged
|
31
|
+
- [ ] Ensure Array and Map nodes return empty ones by default rather than nil
|
data/lib/openapi3_parser.rb
CHANGED
@@ -7,6 +7,12 @@ require "yaml"
|
|
7
7
|
require "json"
|
8
8
|
|
9
9
|
module Openapi3Parser
|
10
|
+
# For a variety of inputs this will construct an OpenAPI document. For a
|
11
|
+
# String/File input it will try to determine if the input is JSON or YAML.
|
12
|
+
#
|
13
|
+
# @param [String, Hash, File] input Source for the OpenAPI document
|
14
|
+
#
|
15
|
+
# @return [Document]
|
10
16
|
def self.load(input)
|
11
17
|
# working_directory ||= if input.respond_to?(:read)
|
12
18
|
# File.dirname(input)
|
@@ -17,6 +23,13 @@ module Openapi3Parser
|
|
17
23
|
Document.new(parse_input(input))
|
18
24
|
end
|
19
25
|
|
26
|
+
# For a given string filename this will read the file and parse it as an
|
27
|
+
# OpenAPI document. It will try detect automatically whether the contents
|
28
|
+
# are JSON or YAML.
|
29
|
+
#
|
30
|
+
# @param [String] path Filename of the OpenAPI document
|
31
|
+
#
|
32
|
+
# @return [Document]
|
20
33
|
def self.load_file(path)
|
21
34
|
file = File.open(path)
|
22
35
|
load(file)
|
@@ -18,12 +18,12 @@ module Openapi3Parser
|
|
18
18
|
def stringify_namespace
|
19
19
|
return "root" if namespace.empty?
|
20
20
|
namespace
|
21
|
-
.map { |i| i.include?("/") ? %("#{i}") : i }
|
21
|
+
.map { |i| i.to_s.include?("/") ? %("#{i}") : i }
|
22
22
|
.join("/")
|
23
23
|
end
|
24
24
|
|
25
25
|
def next_namespace(segment, next_input = nil)
|
26
|
-
next_input ||= input[segment]
|
26
|
+
next_input ||= input.nil? ? nil : input[segment]
|
27
27
|
self.class.new(
|
28
28
|
input: next_input,
|
29
29
|
namespace: namespace + [segment],
|
@@ -12,11 +12,13 @@ module Openapi3Parser
|
|
12
12
|
|
13
13
|
def initialize(
|
14
14
|
context,
|
15
|
+
default: [],
|
15
16
|
value_input_type: nil,
|
16
17
|
value_factory: nil,
|
17
18
|
validate: nil
|
18
19
|
)
|
19
20
|
super(context)
|
21
|
+
@default = default
|
20
22
|
@given_value_input_type = value_input_type
|
21
23
|
@given_value_factory = value_factory
|
22
24
|
@given_validate = validate
|
@@ -24,8 +26,8 @@ module Openapi3Parser
|
|
24
26
|
|
25
27
|
private
|
26
28
|
|
27
|
-
attr_reader :
|
28
|
-
:given_validate
|
29
|
+
attr_reader :default, :given_value_input_type,
|
30
|
+
:given_value_factory, :given_validate
|
29
31
|
|
30
32
|
def process_input(input)
|
31
33
|
input.each_with_index.map do |value, i|
|
@@ -29,8 +29,8 @@ module Openapi3Parser
|
|
29
29
|
field "uniqueItems", input_type: :boolean, default: false
|
30
30
|
field "maxProperties", input_type: Integer
|
31
31
|
field "minProperties", input_type: Integer, default: 0
|
32
|
-
field "required",
|
33
|
-
field "enum",
|
32
|
+
field "required", factory: :required_factory
|
33
|
+
field "enum", factory: :enum_factory
|
34
34
|
|
35
35
|
field "type", input_type: String
|
36
36
|
field "allOf", factory: :referenceable_schema_array
|
@@ -62,6 +62,18 @@ module Openapi3Parser
|
|
62
62
|
Nodes::Schema.new(data, context)
|
63
63
|
end
|
64
64
|
|
65
|
+
def required_factory(context)
|
66
|
+
NodeFactories::Array.new(
|
67
|
+
context,
|
68
|
+
default: nil,
|
69
|
+
value_input_type: String
|
70
|
+
)
|
71
|
+
end
|
72
|
+
|
73
|
+
def enum_factory(context)
|
74
|
+
NodeFactories::Array.new(context, default: nil)
|
75
|
+
end
|
76
|
+
|
65
77
|
def disciminator_factory(context)
|
66
78
|
NodeFactories::Discriminator.new(context)
|
67
79
|
end
|
@@ -88,6 +100,7 @@ module Openapi3Parser
|
|
88
100
|
def referenceable_schema_array(context)
|
89
101
|
NodeFactories::Array.new(
|
90
102
|
context,
|
103
|
+
default: nil,
|
91
104
|
value_factory: NodeFactory::OptionalReference.new(self.class)
|
92
105
|
)
|
93
106
|
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require "openapi3_parser/nodes/server_variable"
|
4
4
|
require "openapi3_parser/node_factory/object"
|
5
|
+
require "openapi3_parser/node_factories/array"
|
5
6
|
|
6
7
|
module Openapi3Parser
|
7
8
|
module NodeFactories
|
@@ -9,15 +10,22 @@ module Openapi3Parser
|
|
9
10
|
include NodeFactory::Object
|
10
11
|
|
11
12
|
allow_extensions
|
12
|
-
field "enum",
|
13
|
+
field "enum", factory: :enum_factory, validate: :validate_enum
|
13
14
|
field "default", input_type: String, required: true
|
14
15
|
field "description", input_type: String
|
15
16
|
|
16
17
|
private
|
17
18
|
|
19
|
+
def enum_factory(context)
|
20
|
+
NodeFactories::Array.new(
|
21
|
+
context,
|
22
|
+
default: nil,
|
23
|
+
value_input_type: String
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
18
27
|
def validate_enum(input)
|
19
28
|
return "Expected atleast one value" if input.empty?
|
20
|
-
"Expected String values" unless input.map(&:class).uniq == [String]
|
21
29
|
end
|
22
30
|
|
23
31
|
def build_object(data, context)
|
@@ -45,6 +45,10 @@ module Openapi3Parser
|
|
45
45
|
@node ||= build_valid_node
|
46
46
|
end
|
47
47
|
|
48
|
+
def nil_input?
|
49
|
+
context.input.nil?
|
50
|
+
end
|
51
|
+
|
48
52
|
private
|
49
53
|
|
50
54
|
def validate(_input, _context); end
|
@@ -69,6 +73,7 @@ module Openapi3Parser
|
|
69
73
|
|
70
74
|
def build_errors
|
71
75
|
error_collection = Validation::ErrorCollection.new
|
76
|
+
return error_collection if nil_input?
|
72
77
|
unless valid_type?
|
73
78
|
error = Validation::Error.new(
|
74
79
|
context.namespace, "Invalid type. #{validate_type}"
|
@@ -80,6 +85,10 @@ module Openapi3Parser
|
|
80
85
|
end
|
81
86
|
|
82
87
|
def build_valid_node
|
88
|
+
if nil_input?
|
89
|
+
return default.nil? ? nil : build_node(processed_input)
|
90
|
+
end
|
91
|
+
|
83
92
|
unless valid_type?
|
84
93
|
raise Openapi3Parser::Error,
|
85
94
|
"Invalid type for #{context.stringify_namespace}. "\
|
@@ -108,7 +117,10 @@ module Openapi3Parser
|
|
108
117
|
end
|
109
118
|
|
110
119
|
def processed_input
|
111
|
-
@processed_input ||=
|
120
|
+
@processed_input ||= begin
|
121
|
+
input = nil_input? ? default : context.input
|
122
|
+
process_input(input)
|
123
|
+
end
|
112
124
|
end
|
113
125
|
|
114
126
|
def process_input(input)
|
@@ -119,6 +131,10 @@ module Openapi3Parser
|
|
119
131
|
input
|
120
132
|
end
|
121
133
|
|
134
|
+
def default
|
135
|
+
nil
|
136
|
+
end
|
137
|
+
|
122
138
|
def extension?(key)
|
123
139
|
key.match(EXTENSION_REGEX)
|
124
140
|
end
|
@@ -53,17 +53,15 @@ module Openapi3Parser
|
|
53
53
|
|
54
54
|
def process_input(input)
|
55
55
|
field_configs.each_with_object(input.dup) do |(field, config), memo|
|
56
|
-
next
|
56
|
+
next unless config.factory?
|
57
57
|
next_context = context.next_namespace(field)
|
58
|
-
memo[field] = config.initialize_factory(
|
59
|
-
next_context, self
|
60
|
-
)
|
58
|
+
memo[field] = config.initialize_factory(next_context, self)
|
61
59
|
end
|
62
60
|
end
|
63
61
|
|
64
62
|
def validate_input(error_collection)
|
65
63
|
super(error_collection)
|
66
|
-
validator = Validator.new(
|
64
|
+
validator = Validator.new(context.input, self)
|
67
65
|
error_collection.tap { |ec| ec.append(*validator.errors) }
|
68
66
|
end
|
69
67
|
|
@@ -16,10 +16,9 @@ module Openapi3Parser
|
|
16
16
|
check_required_fields
|
17
17
|
check_unexpected_fields
|
18
18
|
check_fields_valid
|
19
|
-
|
20
|
-
memo[key] =
|
19
|
+
input.each_with_object({}) do |(key, value), memo|
|
20
|
+
memo[key] = resolve_value(key, value)
|
21
21
|
end
|
22
|
-
apply_defaults(data)
|
23
22
|
end
|
24
23
|
|
25
24
|
private
|
@@ -55,7 +54,8 @@ module Openapi3Parser
|
|
55
54
|
|
56
55
|
def check_type_error(name, field_config)
|
57
56
|
field_context = context.next_namespace(name)
|
58
|
-
|
57
|
+
input = context.input.nil? ? nil : context.input[name]
|
58
|
+
error = field_config.input_type_error(input, factory)
|
59
59
|
|
60
60
|
return unless error
|
61
61
|
raise Openapi3Parser::Error,
|
@@ -65,7 +65,7 @@ module Openapi3Parser
|
|
65
65
|
|
66
66
|
def check_validation_errors(name, field_config)
|
67
67
|
field_context = context.next_namespace(name)
|
68
|
-
errors = field_config.validation_errors(input
|
68
|
+
errors = field_config.validation_errors(field_context.input, factory)
|
69
69
|
|
70
70
|
return unless errors.any?
|
71
71
|
raise Openapi3Parser::Error,
|
@@ -73,10 +73,21 @@ module Openapi3Parser
|
|
73
73
|
"#{errors.join(', ')}"
|
74
74
|
end
|
75
75
|
|
76
|
-
def
|
76
|
+
def resolve_value(key, value)
|
77
77
|
configs = factory.field_configs
|
78
|
-
configs
|
79
|
-
|
78
|
+
return configs[key]&.default(factory) if value.nil?
|
79
|
+
default_value(configs[key], value)
|
80
|
+
end
|
81
|
+
|
82
|
+
def default_value(config, value)
|
83
|
+
resolved_value = value.respond_to?(:node) ? value.node : value
|
84
|
+
|
85
|
+
# let a field config default take precedence if value is a nil_input?
|
86
|
+
if value.respond_to?(:nil_input?) && value.nil_input?
|
87
|
+
default = config&.default(factory)
|
88
|
+
default.nil? ? resolved_value : default
|
89
|
+
else
|
90
|
+
resolved_value
|
80
91
|
end
|
81
92
|
end
|
82
93
|
end
|
@@ -4,11 +4,19 @@ require "openapi3_parser/node/map"
|
|
4
4
|
|
5
5
|
module Openapi3Parser
|
6
6
|
module Nodes
|
7
|
+
# An array within a OpenAPI document.
|
8
|
+
# Very similar to a normal Ruby array, however this is read only and knows
|
9
|
+
# the context of where it sits in an OpenAPI document
|
10
|
+
#
|
11
|
+
# The contents of the data will be dependent on where this document is in
|
12
|
+
# the document hierachy.
|
7
13
|
class Array
|
8
14
|
include Enumerable
|
9
15
|
|
10
16
|
attr_reader :node_data, :node_context
|
11
17
|
|
18
|
+
# @param [::Array] data data used to populate this node
|
19
|
+
# @param [Context] context The context of this node in the document
|
12
20
|
def initialize(data, context)
|
13
21
|
@node_data = data
|
14
22
|
@node_context = context
|
@@ -4,41 +4,53 @@ require "openapi3_parser/node/object"
|
|
4
4
|
|
5
5
|
module Openapi3Parser
|
6
6
|
module Nodes
|
7
|
+
# @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#componentsObject
|
7
8
|
class Components
|
8
9
|
include Node::Object
|
9
10
|
|
11
|
+
# @return [Map] a map of String: {Schema}[../Schema.html] objects
|
10
12
|
def schemas
|
11
13
|
node_data["schemas"]
|
12
14
|
end
|
13
15
|
|
16
|
+
# @return [Map] a map of String: {Response}[./Response.html] objects
|
14
17
|
def responses
|
15
18
|
node_data["responses"]
|
16
19
|
end
|
17
20
|
|
21
|
+
# @return [Map] a map of String: {Parameter}[./Parameter.html] objects
|
18
22
|
def parameters
|
19
23
|
node_data["parameters"]
|
20
24
|
end
|
21
25
|
|
26
|
+
# @return [Map] a map of String: {Example}[../Example.html] objects
|
22
27
|
def examples
|
23
28
|
node_data["examples"]
|
24
29
|
end
|
25
30
|
|
31
|
+
# @return [Map] a map of String: {RequestBody}[./RequestBody.html]
|
32
|
+
# objects
|
26
33
|
def request_bodies
|
27
34
|
node_data["requestBodies"]
|
28
35
|
end
|
29
36
|
|
37
|
+
# @return [Map] a map of String: {Header}[./Header.html] objects
|
30
38
|
def headers
|
31
39
|
node_data["headers"]
|
32
40
|
end
|
33
41
|
|
42
|
+
# @return [Map] a map of String: {SecurityScheme}[./SecurityScheme.html]
|
43
|
+
# objects
|
34
44
|
def security_schemes
|
35
45
|
node_data["securitySchemes"]
|
36
46
|
end
|
37
47
|
|
48
|
+
# @return [Map] a map of String: {Link}[./Link.html] objects
|
38
49
|
def links
|
39
50
|
node_data["links"]
|
40
51
|
end
|
41
52
|
|
53
|
+
# @return [Map] a map of String: {Callback}[./Callback.html] objects
|
42
54
|
def callbacks
|
43
55
|
node_data["callbacks"]
|
44
56
|
end
|
@@ -4,17 +4,21 @@ require "openapi3_parser/node/object"
|
|
4
4
|
|
5
5
|
module Openapi3Parser
|
6
6
|
module Nodes
|
7
|
+
# @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#contactObject
|
7
8
|
class Contact
|
8
9
|
include Node::Object
|
9
10
|
|
11
|
+
# @return [String, nil]
|
10
12
|
def name
|
11
13
|
data["name"]
|
12
14
|
end
|
13
15
|
|
16
|
+
# @return [String, nil]
|
14
17
|
def url
|
15
18
|
data["url"]
|
16
19
|
end
|
17
20
|
|
21
|
+
# @return [String, nil]
|
18
22
|
def email
|
19
23
|
data["email"]
|
20
24
|
end
|