openapi3_parser 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.rspec +1 -0
  4. data/.rubocop.yml +9 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +4 -0
  7. data/Gemfile +5 -0
  8. data/LICENCE +19 -0
  9. data/README.md +32 -0
  10. data/Rakefile +10 -0
  11. data/TODO.md +30 -0
  12. data/lib/openapi3_parser.rb +39 -0
  13. data/lib/openapi3_parser/context.rb +54 -0
  14. data/lib/openapi3_parser/document.rb +48 -0
  15. data/lib/openapi3_parser/error.rb +5 -0
  16. data/lib/openapi3_parser/fields/map.rb +83 -0
  17. data/lib/openapi3_parser/node.rb +115 -0
  18. data/lib/openapi3_parser/node/map.rb +24 -0
  19. data/lib/openapi3_parser/node/object.rb +28 -0
  20. data/lib/openapi3_parser/node_factories/array.rb +105 -0
  21. data/lib/openapi3_parser/node_factories/callback.rb +26 -0
  22. data/lib/openapi3_parser/node_factories/components.rb +83 -0
  23. data/lib/openapi3_parser/node_factories/contact.rb +24 -0
  24. data/lib/openapi3_parser/node_factories/discriminator.rb +31 -0
  25. data/lib/openapi3_parser/node_factories/encoding.rb +34 -0
  26. data/lib/openapi3_parser/node_factories/example.rb +25 -0
  27. data/lib/openapi3_parser/node_factories/external_documentation.rb +23 -0
  28. data/lib/openapi3_parser/node_factories/header.rb +36 -0
  29. data/lib/openapi3_parser/node_factories/info.rb +28 -0
  30. data/lib/openapi3_parser/node_factories/license.rb +22 -0
  31. data/lib/openapi3_parser/node_factories/link.rb +40 -0
  32. data/lib/openapi3_parser/node_factories/map.rb +110 -0
  33. data/lib/openapi3_parser/node_factories/media_type.rb +44 -0
  34. data/lib/openapi3_parser/node_factories/oauth_flow.rb +24 -0
  35. data/lib/openapi3_parser/node_factories/oauth_flows.rb +31 -0
  36. data/lib/openapi3_parser/node_factories/openapi.rb +50 -0
  37. data/lib/openapi3_parser/node_factories/operation.rb +76 -0
  38. data/lib/openapi3_parser/node_factories/parameter.rb +43 -0
  39. data/lib/openapi3_parser/node_factories/parameter/parameter_like.rb +37 -0
  40. data/lib/openapi3_parser/node_factories/path_item.rb +75 -0
  41. data/lib/openapi3_parser/node_factories/paths.rb +32 -0
  42. data/lib/openapi3_parser/node_factories/reference.rb +33 -0
  43. data/lib/openapi3_parser/node_factories/request_body.rb +31 -0
  44. data/lib/openapi3_parser/node_factories/response.rb +45 -0
  45. data/lib/openapi3_parser/node_factories/responses.rb +32 -0
  46. data/lib/openapi3_parser/node_factories/schema.rb +106 -0
  47. data/lib/openapi3_parser/node_factories/security_requirement.rb +25 -0
  48. data/lib/openapi3_parser/node_factories/security_scheme.rb +35 -0
  49. data/lib/openapi3_parser/node_factories/server.rb +32 -0
  50. data/lib/openapi3_parser/node_factories/server_variable.rb +28 -0
  51. data/lib/openapi3_parser/node_factories/tag.rb +24 -0
  52. data/lib/openapi3_parser/node_factories/xml.rb +25 -0
  53. data/lib/openapi3_parser/node_factory.rb +126 -0
  54. data/lib/openapi3_parser/node_factory/field_config.rb +88 -0
  55. data/lib/openapi3_parser/node_factory/map.rb +39 -0
  56. data/lib/openapi3_parser/node_factory/object.rb +80 -0
  57. data/lib/openapi3_parser/node_factory/object/node_builder.rb +85 -0
  58. data/lib/openapi3_parser/node_factory/object/validator.rb +102 -0
  59. data/lib/openapi3_parser/node_factory/optional_reference.rb +23 -0
  60. data/lib/openapi3_parser/nodes/array.rb +26 -0
  61. data/lib/openapi3_parser/nodes/callback.rb +11 -0
  62. data/lib/openapi3_parser/nodes/components.rb +47 -0
  63. data/lib/openapi3_parser/nodes/contact.rb +23 -0
  64. data/lib/openapi3_parser/nodes/discriminator.rb +19 -0
  65. data/lib/openapi3_parser/nodes/encoding.rb +31 -0
  66. data/lib/openapi3_parser/nodes/example.rb +27 -0
  67. data/lib/openapi3_parser/nodes/external_documentation.rb +19 -0
  68. data/lib/openapi3_parser/nodes/header.rb +13 -0
  69. data/lib/openapi3_parser/nodes/info.rb +35 -0
  70. data/lib/openapi3_parser/nodes/license.rb +19 -0
  71. data/lib/openapi3_parser/nodes/link.rb +35 -0
  72. data/lib/openapi3_parser/nodes/map.rb +11 -0
  73. data/lib/openapi3_parser/nodes/media_type.rb +27 -0
  74. data/lib/openapi3_parser/nodes/oauth_flow.rb +27 -0
  75. data/lib/openapi3_parser/nodes/oauth_flows.rb +27 -0
  76. data/lib/openapi3_parser/nodes/openapi.rb +44 -0
  77. data/lib/openapi3_parser/nodes/operation.rb +59 -0
  78. data/lib/openapi3_parser/nodes/parameter.rb +21 -0
  79. data/lib/openapi3_parser/nodes/parameter/parameter_like.rb +53 -0
  80. data/lib/openapi3_parser/nodes/path_item.rb +59 -0
  81. data/lib/openapi3_parser/nodes/paths.rb +11 -0
  82. data/lib/openapi3_parser/nodes/request_body.rb +23 -0
  83. data/lib/openapi3_parser/nodes/response.rb +27 -0
  84. data/lib/openapi3_parser/nodes/responses.rb +15 -0
  85. data/lib/openapi3_parser/nodes/schema.rb +159 -0
  86. data/lib/openapi3_parser/nodes/security_requirement.rb +11 -0
  87. data/lib/openapi3_parser/nodes/security_scheme.rb +44 -0
  88. data/lib/openapi3_parser/nodes/server.rb +25 -0
  89. data/lib/openapi3_parser/nodes/server_variable.rb +23 -0
  90. data/lib/openapi3_parser/nodes/tag.rb +23 -0
  91. data/lib/openapi3_parser/nodes/xml.rb +31 -0
  92. data/lib/openapi3_parser/validation/error.rb +14 -0
  93. data/lib/openapi3_parser/validation/error_collection.rb +36 -0
  94. data/lib/openapi3_parser/version.rb +5 -0
  95. data/openapi3_parser.gemspec +28 -0
  96. metadata +208 -0
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/node_factory/object/validator"
4
+ require "openapi3_parser/error"
5
+
6
+ module Openapi3Parser
7
+ module NodeFactory
8
+ module Object
9
+ class NodeBuilder
10
+ def initialize(input, factory)
11
+ @input = input
12
+ @factory = factory
13
+ end
14
+
15
+ def data
16
+ check_required_fields
17
+ check_unexpected_fields
18
+ check_fields_valid
19
+ data = input.each_with_object({}) do |(key, value), memo|
20
+ memo[key] = value.respond_to?(:node) ? value.node : value
21
+ end
22
+ apply_defaults(data)
23
+ end
24
+
25
+ private
26
+
27
+ attr_reader :input, :factory
28
+
29
+ def context
30
+ factory.context
31
+ end
32
+
33
+ def check_required_fields
34
+ fields = Validator.missing_required_fields(input, factory)
35
+ return if fields.empty?
36
+ raise Openapi3Parser::Error,
37
+ "Missing required fields for "\
38
+ "#{context.stringify_namespace}: #{fields.join(', ')}"
39
+ end
40
+
41
+ def check_unexpected_fields
42
+ fields = Validator.unexpected_fields(input, factory)
43
+ return if fields.empty?
44
+ raise Openapi3Parser::Error,
45
+ "Unexpected fields for #{context.stringify_namespace}: "\
46
+ "#{fields.join(', ')}"
47
+ end
48
+
49
+ def check_fields_valid
50
+ factory.field_configs.each do |name, field_config|
51
+ check_type_error(name, field_config)
52
+ check_validation_errors(name, field_config)
53
+ end
54
+ end
55
+
56
+ def check_type_error(name, field_config)
57
+ field_context = context.next_namespace(name)
58
+ error = field_config.input_type_error(input[name], factory)
59
+
60
+ return unless error
61
+ raise Openapi3Parser::Error,
62
+ "Invalid type for "\
63
+ "#{field_context.stringify_namespace}: #{error}"
64
+ end
65
+
66
+ def check_validation_errors(name, field_config)
67
+ field_context = context.next_namespace(name)
68
+ errors = field_config.validation_errors(input[name], factory)
69
+
70
+ return unless errors.any?
71
+ raise Openapi3Parser::Error,
72
+ "Invalid field for #{field_context.stringify_namespace}: "\
73
+ "#{errors.join(', ')}"
74
+ end
75
+
76
+ def apply_defaults(data)
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?
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/node_factory"
4
+ require "openapi3_parser/validation/error"
5
+
6
+ module Openapi3Parser
7
+ module NodeFactory
8
+ module Object
9
+ class Validator
10
+ def self.missing_required_fields(input, factory)
11
+ configs = factory.field_configs
12
+ configs.each_with_object([]) do |(name, field_config), memo|
13
+ memo << name if field_config.required?(factory) && input[name].nil?
14
+ end
15
+ end
16
+
17
+ def self.unexpected_fields(input, factory)
18
+ unexpected_keys = input.keys - factory.field_configs.keys
19
+ if factory.allowed_extensions?
20
+ unexpected_keys.reject { |k| k =~ NodeFactory::EXTENSION_REGEX }
21
+ else
22
+ unexpected_keys
23
+ end
24
+ end
25
+
26
+ def initialize(input, factory)
27
+ @input = input
28
+ @factory = factory
29
+ end
30
+
31
+ def errors
32
+ [
33
+ missing_required_fields_error,
34
+ unexpected_fields_error,
35
+ invalid_field_errors
36
+ ].flatten.compact
37
+ end
38
+
39
+ private
40
+
41
+ attr_reader :input, :factory
42
+
43
+ def context
44
+ factory.context
45
+ end
46
+
47
+ def missing_required_fields_error
48
+ fields = self.class.missing_required_fields(input, factory)
49
+ return unless fields.any?
50
+ Validation::Error.new(
51
+ context.namespace,
52
+ "Missing required fields: #{fields.join(', ')}"
53
+ )
54
+ end
55
+
56
+ def unexpected_fields_error
57
+ fields = self.class.unexpected_fields(input, factory)
58
+ return unless fields.any?
59
+ Validation::Error.new(
60
+ context.namespace,
61
+ "Unexpected fields: #{fields.join(', ')}"
62
+ )
63
+ end
64
+
65
+ def invalid_field_errors
66
+ factory.field_configs.inject([]) do |memo, (name, field_config)|
67
+ memo + field_errors(name, field_config)
68
+ end
69
+ end
70
+
71
+ def field_errors(name, field_config)
72
+ field = input[name]
73
+ return [] if field.nil?
74
+ return field.errors.to_a if field.respond_to?(:errors)
75
+ type_error = build_type_error(name, field_config)
76
+ return [type_error] if type_error
77
+ build_validation_errors(name, field_config)
78
+ end
79
+
80
+ def build_type_error(name, field_config)
81
+ type_error = field_config.input_type_error(input[name], factory)
82
+ return unless type_error
83
+ Validation::Error.new(
84
+ context.next_namespace(name),
85
+ "Invalid type: #{type_error}"
86
+ )
87
+ end
88
+
89
+ def build_validation_errors(name, field_config)
90
+ field_config.validation_errors(
91
+ input[name], factory
92
+ ).map do |error|
93
+ Validation::Error.new(
94
+ context.next_namespace(name),
95
+ "Invalid field: #{error}"
96
+ )
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/node_factories/reference"
4
+
5
+ module Openapi3Parser
6
+ module NodeFactory
7
+ class OptionalReference
8
+ def initialize(factory)
9
+ @factory = factory
10
+ end
11
+
12
+ def call(context)
13
+ reference = context.input.is_a?(Hash) && context.input["$ref"]
14
+ return NodeFactories::Reference.new(context, self) if reference
15
+ factory.new(context)
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :factory
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/node/map"
4
+
5
+ module Openapi3Parser
6
+ module Nodes
7
+ class Array
8
+ include Enumerable
9
+
10
+ attr_reader :node_data, :node_context
11
+
12
+ def initialize(data, context)
13
+ @node_data = data
14
+ @node_context = context
15
+ end
16
+
17
+ def [](value)
18
+ node_data[value]
19
+ end
20
+
21
+ def each(&block)
22
+ node_data.each(&block)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/node/map"
4
+
5
+ module Openapi3Parser
6
+ module Nodes
7
+ class Callback
8
+ include Node::Map
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/node/object"
4
+
5
+ module Openapi3Parser
6
+ module Nodes
7
+ class Components
8
+ include Node::Object
9
+
10
+ def schemas
11
+ node_data["schemas"]
12
+ end
13
+
14
+ def responses
15
+ node_data["responses"]
16
+ end
17
+
18
+ def parameters
19
+ node_data["parameters"]
20
+ end
21
+
22
+ def examples
23
+ node_data["examples"]
24
+ end
25
+
26
+ def request_bodies
27
+ node_data["requestBodies"]
28
+ end
29
+
30
+ def headers
31
+ node_data["headers"]
32
+ end
33
+
34
+ def security_schemes
35
+ node_data["securitySchemes"]
36
+ end
37
+
38
+ def links
39
+ node_data["links"]
40
+ end
41
+
42
+ def callbacks
43
+ node_data["callbacks"]
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/node/object"
4
+
5
+ module Openapi3Parser
6
+ module Nodes
7
+ class Contact
8
+ include Node::Object
9
+
10
+ def name
11
+ data["name"]
12
+ end
13
+
14
+ def url
15
+ data["url"]
16
+ end
17
+
18
+ def email
19
+ data["email"]
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/node/object"
4
+
5
+ module Openapi3Parser
6
+ module Nodes
7
+ class Discriminator
8
+ include Node::Object
9
+
10
+ def property_name
11
+ node_data["propertyName"]
12
+ end
13
+
14
+ def mapping
15
+ node_data["mapping"]
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/node/object"
4
+
5
+ module Openapi3Parser
6
+ module Nodes
7
+ class Encoding
8
+ include Node::Object
9
+
10
+ def content_type
11
+ node_data["contentType"]
12
+ end
13
+
14
+ def headers
15
+ node_data["headers"]
16
+ end
17
+
18
+ def style
19
+ node_data["style"]
20
+ end
21
+
22
+ def explode?
23
+ node_data["explode"]
24
+ end
25
+
26
+ def allow_reserved?
27
+ node_data["allowReserved"]
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/node/object"
4
+
5
+ module Openapi3Parser
6
+ module Nodes
7
+ class Example
8
+ include Node::Object
9
+
10
+ def summary
11
+ node_data["summary"]
12
+ end
13
+
14
+ def description
15
+ node_data["description"]
16
+ end
17
+
18
+ def value
19
+ node_data["value"]
20
+ end
21
+
22
+ def external_value
23
+ node_data["externalValue"]
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/node/object"
4
+
5
+ module Openapi3Parser
6
+ module Nodes
7
+ class ExternalDocumentation
8
+ include Node::Object
9
+
10
+ def description
11
+ node_data["description"]
12
+ end
13
+
14
+ def url
15
+ node_data["url"]
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/node/object"
4
+ require "openapi3_parser/nodes/parameter/parameter_like"
5
+
6
+ module Openapi3Parser
7
+ module Nodes
8
+ class Header
9
+ include Node::Object
10
+ include Parameter::ParameterLike
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openapi3_parser/node/object"
4
+
5
+ module Openapi3Parser
6
+ module Nodes
7
+ class Info
8
+ include Node::Object
9
+
10
+ def title
11
+ node_data["title"]
12
+ end
13
+
14
+ def description
15
+ node_data["description"]
16
+ end
17
+
18
+ def terms_of_service
19
+ node_data["termsOfService"]
20
+ end
21
+
22
+ def contact
23
+ node_data["contact"]
24
+ end
25
+
26
+ def license
27
+ node_data["license"]
28
+ end
29
+
30
+ def version
31
+ node_data["version"]
32
+ end
33
+ end
34
+ end
35
+ end