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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/CHANGELOG.md +6 -0
  4. data/README.md +5 -1
  5. data/TODO.md +1 -0
  6. data/lib/openapi3_parser.rb +13 -0
  7. data/lib/openapi3_parser/context.rb +2 -2
  8. data/lib/openapi3_parser/node_factories/array.rb +4 -2
  9. data/lib/openapi3_parser/node_factories/components.rb +4 -0
  10. data/lib/openapi3_parser/node_factories/schema.rb +15 -2
  11. data/lib/openapi3_parser/node_factories/server_variable.rb +10 -2
  12. data/lib/openapi3_parser/node_factory.rb +17 -1
  13. data/lib/openapi3_parser/node_factory/map.rb +4 -0
  14. data/lib/openapi3_parser/node_factory/object.rb +3 -5
  15. data/lib/openapi3_parser/node_factory/object/node_builder.rb +19 -8
  16. data/lib/openapi3_parser/nodes/array.rb +8 -0
  17. data/lib/openapi3_parser/nodes/callback.rb +1 -0
  18. data/lib/openapi3_parser/nodes/components.rb +12 -0
  19. data/lib/openapi3_parser/nodes/contact.rb +4 -0
  20. data/lib/openapi3_parser/nodes/discriminator.rb +3 -0
  21. data/lib/openapi3_parser/nodes/encoding.rb +6 -0
  22. data/lib/openapi3_parser/nodes/example.rb +5 -0
  23. data/lib/openapi3_parser/nodes/external_documentation.rb +3 -0
  24. data/lib/openapi3_parser/nodes/header.rb +1 -0
  25. data/lib/openapi3_parser/nodes/info.rb +7 -0
  26. data/lib/openapi3_parser/nodes/license.rb +3 -0
  27. data/lib/openapi3_parser/nodes/link.rb +7 -0
  28. data/lib/openapi3_parser/nodes/map.rb +6 -0
  29. data/lib/openapi3_parser/nodes/media_type.rb +5 -0
  30. data/lib/openapi3_parser/nodes/oauth_flow.rb +5 -0
  31. data/lib/openapi3_parser/nodes/oauth_flows.rb +5 -0
  32. data/lib/openapi3_parser/nodes/openapi.rb +11 -0
  33. data/lib/openapi3_parser/nodes/operation.rb +16 -0
  34. data/lib/openapi3_parser/nodes/parameter.rb +3 -0
  35. data/lib/openapi3_parser/nodes/parameter/parameter_like.rb +14 -0
  36. data/lib/openapi3_parser/nodes/path_item.rb +14 -0
  37. data/lib/openapi3_parser/nodes/paths.rb +1 -0
  38. data/lib/openapi3_parser/nodes/request_body.rb +4 -0
  39. data/lib/openapi3_parser/nodes/response.rb +5 -0
  40. data/lib/openapi3_parser/nodes/responses.rb +2 -0
  41. data/lib/openapi3_parser/nodes/schema.rb +38 -0
  42. data/lib/openapi3_parser/nodes/security_requirement.rb +1 -0
  43. data/lib/openapi3_parser/nodes/security_scheme.rb +9 -0
  44. data/lib/openapi3_parser/nodes/server.rb +5 -2
  45. data/lib/openapi3_parser/nodes/server_variable.rb +4 -0
  46. data/lib/openapi3_parser/nodes/tag.rb +4 -0
  47. data/lib/openapi3_parser/nodes/xml.rb +8 -2
  48. data/lib/openapi3_parser/version.rb +1 -1
  49. metadata +3 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3c7e2585cb3bbdbda459519eb7e264dfd89f5745
4
- data.tar.gz: 4fdbb4b547e626e1b0ba5f502b93107638af3655
3
+ metadata.gz: f60ae34f39675f7ce3616bd96dc3e383275d117d
4
+ data.tar.gz: 4ecf6bffd69c875778c4d096f29cf7b5deadbf7e
5
5
  SHA512:
6
- metadata.gz: 498d2043a338970c66ef9d14590adb34ec2f7b65e751985f8d12a8c9506d63e09a9840e7521b00a953000af1e286917147fb4507be29f68a5c047aa9f124f7d8
7
- data.tar.gz: 7fb4d6b168b514fa01056fa5be0026551ad02e0e47506e99516b14b290e450c0940031e82fc38bdc0f4c5d137d98d3a621f28d42bd6e5923f335a7c31255796e
6
+ metadata.gz: f5a96679f760117e345c9e992161444c06df7d667953fad6badf547dd83dee449b672cc9f265a26a7166e2cdec887d5205bf0dcda6abdbece2a2ce74aeb61153
7
+ data.tar.gz: 087aea7ab5f4abceb69b9acce6854f70dac44fca1620bde695d7dd1a7813ca1a468728e3cc5a08ab5ae31d5320c75459f9537ce584c6ffbff082ca796d9a3602
data/.gitignore CHANGED
@@ -1 +1,4 @@
1
1
  /Gemfile.lock
2
+ /pkg
3
+ /.yardoc
4
+ /doc
@@ -0,0 +1,6 @@
1
+ # 0.2.0
2
+
3
+ - Allow defaulting to empty arrays and maps
4
+ - Configure rubydoc
5
+ - Types returned documented for the nodes
6
+
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # OpenAPI 3 Parser
2
2
 
3
- [![Build Status](https://travis-ci.org/kevindew/openapi_parser.svg?branch=master)](https://travis-ci.org/kevindew/openapi_parser)
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
@@ -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 :given_value_input_type, :given_value_factory,
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|
@@ -78,6 +78,10 @@ module Openapi3Parser
78
78
  value_factory: NodeFactory::OptionalReference.new(factory)
79
79
  )
80
80
  end
81
+
82
+ def default
83
+ {}
84
+ end
81
85
  end
82
86
  end
83
87
  end
@@ -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", input_type: ::Array
33
- field "enum", input_type: ::Array
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", input_type: ::Array, validate: :validate_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 ||= process_input(context.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
@@ -34,6 +34,10 @@ module Openapi3Parser
34
34
  def build_map(data, _)
35
35
  data
36
36
  end
37
+
38
+ def default
39
+ {}
40
+ end
37
41
  end
38
42
  end
39
43
  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 if !config.factory? || !memo[field]
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(processed_input, self)
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
- data = input.each_with_object({}) do |(key, value), memo|
20
- memo[key] = value.respond_to?(:node) ? value.node : value
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
- error = field_config.input_type_error(input[name], factory)
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[name], factory)
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 apply_defaults(data)
76
+ def resolve_value(key, value)
77
77
  configs = factory.field_configs
78
- configs.each_with_object(data) do |(name, field_config), _memo|
79
- data[name] = field_config.default(factory) if data[name].nil?
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,6 +4,7 @@ require "openapi3_parser/node/map"
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#callbackObject
7
8
  class Callback
8
9
  include Node::Map
9
10
  end
@@ -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