openapi3_parser 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
[![Build Status](https://travis-ci.org/kevindew/
|
3
|
+
[![Build Status](https://travis-ci.org/kevindew/openapi3_parser.svg?branch=master)](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
|