openapi_parser 0.1.0 → 0.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: be5f0f122cae14b6ae5d17dbc537b63aba01f0f26c677b400c77b5befc3fe43c
4
- data.tar.gz: bbdd0f1318dfb9465f7f545545198ce2e3189c2baf8823b85e7c0eab6ed30bc5
3
+ metadata.gz: ee6c1b21577fd0129c63e8b80fab4f929cccd3220d7888af95bd38f19665e994
4
+ data.tar.gz: 1107cd65d31bed5e98f2aad6a5629e87b0bd031c1c23e81e2357f4e2cf6dbad2
5
5
  SHA512:
6
- metadata.gz: c9bc537c05becea794bbe244bcaa8afbc4471c9d64eb142139fbd46adf7efe37d216a0f2890d9d58358d1ba1f371f1fc6a7e704f164b0dc8dd53e41006091206
7
- data.tar.gz: 686e47b13639f61f026c75af5eef0a96a1ab7948a4eea592ccaed0f946e5e187b89641d91038142739396cf9a79d1360b1f45e67d996fa07911380c7b532373f
6
+ metadata.gz: 349707da91353ab6a915b192656731d098c8fc45944ac30f2f25569c9ad1379b72909ef1cf305c950a9afc2c3477414d2c457312d9f88a5030fdf04ea30d26b9
7
+ data.tar.gz: 06e38d3763f60731baeb3cf650978ad5bcd6ced36701e50122f31df7a2a9855c22e77e75867dec3f63d201878bad10c51d00bf38c560ab35ca3725d502d6807a
data/.gitignore CHANGED
@@ -9,3 +9,4 @@
9
9
 
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
+ Gemfile.lock
data/.rubocop.yml ADDED
@@ -0,0 +1,10 @@
1
+ inherit_gem:
2
+ fincop:
3
+ - 'config/rails.yml'
4
+ - 'config/rspec.yml'
5
+ - 'config/rubocop.yml'
6
+ # If you are using Rails 4, activate this cop.
7
+ # - 'config/disabled_for_rails_4.yml'
8
+
9
+ AllCops:
10
+ TargetRubyVersion: 2.5
data/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
 
3
- git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
3
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
5
  # Specify your gem's dependencies in openapi_parser.gemspec
6
6
  gemspec
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # OpenapiParser
1
+ # OpenAPI Parser
2
2
 
3
3
  Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/openapi_parser`. To experiment with that code, run `bin/console` for an interactive prompt.
4
4
 
@@ -40,4 +40,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
40
40
 
41
41
  ## Code of Conduct
42
42
 
43
- Everyone interacting in the OpenapiParser project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/openapi_parser/blob/master/CODE_OF_CONDUCT.md).
43
+ Everyone interacting in the OpenAPIParser project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/openapi_parser/blob/master/CODE_OF_CONDUCT.md).
data/Rakefile CHANGED
@@ -1,5 +1,5 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
5
5
 
@@ -1,5 +1,10 @@
1
- require "openapi_parser/version"
1
+ require 'openapi_parser/version'
2
+ require 'openapi_parser/concern'
3
+ require 'openapi_parser/schemas'
4
+ require 'openapi_parser/path_item_finder'
5
+ require 'openapi_parser/request_operation'
6
+ require 'openapi_parser/schema_validator'
2
7
 
3
- module OpenapiParser
8
+ module OpenAPIParser
4
9
  # Your code goes here...
5
10
  end
@@ -0,0 +1,2 @@
1
+ require_relative 'concerns/parseable'
2
+ require_relative 'concerns/findable'
@@ -0,0 +1,22 @@
1
+ module OpenAPIParser::Findable
2
+ # @param [String] reference
3
+ # @return [OpenAPIParser::Findable]
4
+ def find_object(reference)
5
+ return nil unless reference.start_with?(object_reference)
6
+ return self if object_reference == reference
7
+
8
+ @find_object_cache = {} unless defined? @find_object_cache
9
+ if (obj = @find_object_cache[reference])
10
+ return obj
11
+ end
12
+
13
+ _openapi_all_child_objects.each do |c|
14
+ if (obj = c.find_object(reference))
15
+ @find_object_cache[reference] = obj
16
+ return obj
17
+ end
18
+ end
19
+
20
+ nil
21
+ end
22
+ end
@@ -0,0 +1,232 @@
1
+ module OpenAPIParser::Parseable
2
+ def self.included(base)
3
+ base.extend(ClassMethods)
4
+ end
5
+ module ClassMethods
6
+ attr_reader :_openapi_attr_values,
7
+ :_openapi_attr_list_objects,
8
+ :_openapi_attr_objects,
9
+ :_openapi_attr_hash_objects,
10
+ :_openapi_attr_hash_body_objects
11
+
12
+ # no option support
13
+ def openapi_attr_values(*names)
14
+ names.each { |name| openapi_attr_value(name) }
15
+ end
16
+
17
+ def openapi_attr_value(name, options = {})
18
+ @_openapi_attr_values = {} unless defined?(@_openapi_attr_values)
19
+
20
+ attr_reader name
21
+ @_openapi_attr_values[name] = options
22
+ end
23
+
24
+ # no option support
25
+ def openapi_attr_objects(*names, klass)
26
+ names.each { |name| openapi_attr_object(name, klass) }
27
+ end
28
+
29
+ def openapi_attr_object(name, klass, options = {})
30
+ @_openapi_attr_objects = {} unless defined?(@_openapi_attr_objects )
31
+
32
+ attr_reader name
33
+ @_openapi_attr_objects[name] = options.merge(klass: klass)
34
+ end
35
+
36
+ def openapi_attr_list_object(name, klass, options = {})
37
+ @_openapi_attr_list_objects = {} unless defined?(@_openapi_attr_list_objects)
38
+
39
+ attr_reader name
40
+ @_openapi_attr_list_objects[name] = options.merge(klass: klass)
41
+ end
42
+
43
+ def openapi_attr_hash_object(name, klass, options = {})
44
+ @_openapi_attr_hash_objects = {} unless defined?(@_openapi_attr_hash_objects)
45
+
46
+ attr_reader name
47
+ @_openapi_attr_hash_objects[name] = options.merge(klass: klass)
48
+ end
49
+
50
+ def openapi_attr_hash_body_objects(name, klass, options = {})
51
+ @_openapi_attr_hash_body_objects = {} unless defined?(@_openapi_attr_hash_body_objects)
52
+
53
+ options[:reject_keys] = options[:reject_keys] ? options[:reject_keys].map(&:to_s) : []
54
+
55
+ attr_reader name
56
+ @_openapi_attr_hash_body_objects[name] = options.merge(klass: klass)
57
+ end
58
+ end
59
+
60
+
61
+ def _openapi_all_child_objects
62
+ @_openapi_all_child_objects ||= []
63
+ end
64
+
65
+ def _add_child_object(object)
66
+ return unless object.is_a?(OpenAPIParser::Parseable)
67
+ _openapi_all_child_objects << object
68
+ end
69
+
70
+
71
+ def load_data
72
+ create_attr_values(self.class._openapi_attr_values)
73
+
74
+ create_attr_objects(self.class._openapi_attr_objects)
75
+ create_attr_list_objects(self.class._openapi_attr_list_objects)
76
+ create_attr_hash_objects(self.class._openapi_attr_hash_objects)
77
+ create_attr_hash_body_objects(self.class._openapi_attr_hash_body_objects)
78
+ end
79
+
80
+ def create_attr_list_objects(settings)
81
+ return unless settings
82
+
83
+ settings.each do |variable_name, options|
84
+ ref_name_base = options[:schema_key] ? options[:schema_key] : variable_name
85
+ klass = options[:klass]
86
+ allow_reference = options[:reference] || false
87
+ allow_data_type = options[:allow_data_type]
88
+
89
+ create_attr_list_object(variable_name, raw_schema[ref_name_base.to_s], ref_name_base, klass, allow_reference, allow_data_type)
90
+ end
91
+ end
92
+
93
+ def create_attr_hash_objects(settings)
94
+ return unless settings
95
+
96
+ settings.each do |variable_name, options|
97
+ ref_name_base = options[:schema_key] ? options[:schema_key] : variable_name
98
+ klass = options[:klass]
99
+ allow_reference = options[:reference] || false
100
+ allow_data_type = options[:allow_data_type]
101
+
102
+ create_attr_hash_object(variable_name, raw_schema[ref_name_base .to_s], ref_name_base, klass, allow_reference, allow_data_type)
103
+ end
104
+ end
105
+
106
+ def create_attr_objects(values)
107
+ return unless values
108
+
109
+ values.each do |name, options|
110
+ key = options[:schema_key] ? options[:schema_key] : name
111
+ klass = options[:klass]
112
+ allow_reference = options[:reference] || false
113
+ allow_data_type = options[:allow_data_type]
114
+
115
+ obj = create_attr_object(name, key, raw_schema[key.to_s], klass, allow_reference, allow_data_type)
116
+ _add_child_object(obj)
117
+ end
118
+ end
119
+
120
+ def create_attr_hash_body_objects(values)
121
+ return unless values
122
+
123
+ values.each do |name, options|
124
+ klass = options[:klass]
125
+ allow_reference = options[:reference] || false
126
+ allow_data_type = options[:allow_data_type]
127
+ reject_keys = options[:reject_keys]
128
+
129
+ create_hash_body_objects(name, raw_schema, klass, allow_reference, allow_data_type, reject_keys)
130
+ end
131
+ end
132
+
133
+ def create_attr_values(values)
134
+ return unless values
135
+
136
+ values.each do |variable_name, options|
137
+ key = options[:schema_key] ? options[:schema_key] : variable_name
138
+
139
+ create_variable(variable_name, raw_schema[key.to_s])
140
+ end
141
+ end
142
+
143
+
144
+ # for responses and paths object
145
+ def create_hash_body_objects(name, schema, klass, allow_reference, allow_data_type, reject_keys)
146
+ unless schema
147
+ create_variable(name, nil)
148
+ return
149
+ end
150
+
151
+ objects = schema.reject{|k, _| reject_keys.include?(k)}.map do |name, child_schema|
152
+ [
153
+ name.to_s, # support string key only in OpenAPI3
154
+ build_openapi_object(escape_reference(name), child_schema, klass, allow_reference, allow_data_type)
155
+ ]
156
+ end.to_h
157
+
158
+ create_variable(name, objects)
159
+ objects.values.each { |o| _add_child_object(o) }
160
+ end
161
+
162
+ # @return [OpenAPIParser::Schemas::Base]
163
+ def create_attr_object(variable_name, ref_name, schema, klass, allow_reference, allow_data_type)
164
+ data = build_openapi_object(ref_name, schema, klass, allow_reference, allow_data_type)
165
+ create_variable(variable_name, data)
166
+ data
167
+ end
168
+
169
+ def create_attr_hash_object(variable_name, hash_schema, ref_name_base, klass, allow_reference, allow_data_type)
170
+ data = if hash_schema
171
+ hash_schema.map { |key, s| [key, build_openapi_object([ref_name_base, key], s, klass, allow_reference, allow_data_type) ]}.to_h
172
+ else
173
+ nil
174
+ end
175
+
176
+ create_variable(variable_name, data)
177
+ data.values.each { |obj| _add_child_object(obj) } if data
178
+ end
179
+
180
+ def create_attr_list_object(variable_name, array_schema, ref_name_base, klass, allow_reference, allow_data_type)
181
+ data = if array_schema
182
+ array_schema.map.with_index { |s, idx| build_openapi_object([ref_name_base, idx], s, klass, allow_reference, allow_data_type) }
183
+ else
184
+ nil
185
+ end
186
+
187
+ create_variable(variable_name, data)
188
+ data.each { |obj| _add_child_object(obj) } if data
189
+ end
190
+
191
+
192
+ # create instance variable @variable_name using data
193
+ # @param [String] variable_name
194
+ # @param [Object] data
195
+ def create_variable(variable_name, data)
196
+ instance_variable_set("@#{variable_name}", data)
197
+ end
198
+
199
+ # return nil, klass, Reference
200
+ def build_openapi_object(ref_names, schema, klass, allow_reference, allow_data_type)
201
+ return nil unless schema
202
+
203
+ if allow_data_type && !check_object_schema?(schema)
204
+ schema
205
+ elsif allow_reference && check_reference_schema?(schema)
206
+ OpenAPIParser::Schemas::Reference.new(build_object_reference(ref_names), self, self.root, schema)
207
+ else
208
+ klass.new(build_object_reference(ref_names), self, self.root, schema)
209
+ end
210
+ end
211
+
212
+ # @return Boolean
213
+ def check_reference_schema?(check_schema)
214
+ check_object_schema?(check_schema) && !check_schema['$ref'].nil?
215
+ end
216
+
217
+ def check_object_schema?(check_schema)
218
+ check_schema.is_a?(Hash)
219
+ end
220
+
221
+ def escape_reference(str)
222
+ str.to_s.gsub('/', '~1')
223
+ end
224
+
225
+ # @return [String]
226
+ def build_object_reference(names)
227
+ names = [names] unless names.is_a?(Array)
228
+ ref = names.map{ |n| escape_reference(n)}.join('/')
229
+
230
+ "#{object_reference}/#{ref}"
231
+ end
232
+ end
@@ -0,0 +1,93 @@
1
+ class OpenAPIParser::PathItemFinder
2
+ # @param [OpenAPIParser::Schemas::Paths] paths
3
+ def initialize(paths)
4
+ @root = PathNode.new('/')
5
+ @paths = paths
6
+
7
+ @paths.path.each { |path, _path_item_object| @root.register_path_node(path.split("/"), path) }
8
+ end
9
+
10
+ # @param [String, Symbol] http_method like (get, post .... allow symbol)
11
+ # @param [String] request_path
12
+ # @return [OpenAPIParser::Schemas::Paths]
13
+ def operation_object(http_method, request_path)
14
+ if (path_item_object = @paths.path[request_path])
15
+ if (op = path_item_object.operation(http_method))
16
+ return op, {} # find no path_params path
17
+ end
18
+ end
19
+
20
+ # check with path_params
21
+ parse_request_path(http_method, request_path)
22
+ end
23
+
24
+ class PathNode
25
+ attr_accessor :full_path, :name
26
+
27
+ def initialize(name)
28
+ @name = name
29
+ @children = Hash.new {|h, k| h[k] = PathNode.new(k) }
30
+ @path_template_node = nil # we can't initialize because recursive initialize...
31
+ @full_path = nil
32
+ end
33
+
34
+ def register_path_node(splited_path, full_path)
35
+ if splited_path.empty?
36
+ @full_path = full_path
37
+ return
38
+ end
39
+
40
+ path_name = splited_path.shift
41
+
42
+ child = path_template?(path_name) ? path_template_node(path_name) : children[path_name]
43
+ child.register_path_node(splited_path, full_path)
44
+ end
45
+
46
+ # @return [String, nil] and Hash
47
+ def find_full_path(splited_path)
48
+ return [@full_path, {}] if splited_path.empty?
49
+
50
+ path_name = splited_path.shift
51
+
52
+ # when ambiguous matching like this
53
+ # /{entity}/me
54
+ # /books/{id}
55
+ # OpenAPI3 depend on the tooling so we use concrete one (using /books/)
56
+
57
+ path_params = {}
58
+ if children.key?(path_name)
59
+ child = children[path_name]
60
+ else
61
+ child = path_template_node(path_name)
62
+ path_params = {"#{child.name}" =>path_name}
63
+ end
64
+
65
+ ret, other_path_params = child.find_full_path(splited_path)
66
+ [ret, path_params.merge(other_path_params)]
67
+ end
68
+
69
+ private
70
+
71
+ attr_reader :children
72
+
73
+ def path_template_node(path_name)
74
+ @path_template_node ||= PathNode.new(path_name[1..(path_name.length-2)]) # delete {} from {name}
75
+ end
76
+
77
+ def path_template?(path_name)
78
+ path_name.start_with?('{') && path_name.end_with?('}')
79
+ end
80
+ end
81
+
82
+ private
83
+
84
+ def parse_request_path(http_method, request_path)
85
+ original_path, path_params = @root.find_full_path(request_path.split("/"))
86
+ return nil, path_params unless original_path
87
+
88
+ path_item_object = @paths.path[original_path]
89
+ obj = path_item_object.operation(http_method.to_s)
90
+
91
+ [obj, path_params]
92
+ end
93
+ end
@@ -0,0 +1,30 @@
1
+ # binding request data and operation object
2
+
3
+ class OpenAPIParser::RequestOperation
4
+ class << self
5
+ # @param [OpenAPIParser::PathItemFinder] path_item_finder
6
+ def create(http_method, request_path, path_item_finder)
7
+ endpoint, path_params = path_item_finder.operation_object(http_method, request_path)
8
+
9
+ return nil unless endpoint
10
+
11
+ self.new(endpoint, path_params)
12
+ end
13
+ end
14
+
15
+ # @!attribute [r] operation_object
16
+ # @return [OpenAPIParser::Schemas::Operation, nil]
17
+ # @!attribute [r] path_params
18
+ # @return [Hash{String => String}]
19
+ attr_reader :operation_object, :path_params
20
+
21
+ def initialize(operation_object, path_params)
22
+ @operation_object = operation_object
23
+ @path_params = path_params || {}
24
+ end
25
+
26
+ # support application/json only :(
27
+ def validate_request_body(content_type, params)
28
+ operation_object&.validate_request_body(content_type, params)
29
+ end
30
+ end
@@ -0,0 +1,172 @@
1
+ class OpenAPIParser::SchemaValidator
2
+ class ValidateError < StandardError
3
+ def initialize(data, type, reference)
4
+ @data = data
5
+ @type = type
6
+ @reference = reference
7
+ end
8
+
9
+ def message
10
+ "#{@data} class is #{@data.class} but it's not valid #{@type} in #{@reference}"
11
+ end
12
+ end
13
+
14
+ class NotNullError < StandardError
15
+ def initialize(reference)
16
+ @reference = reference
17
+ end
18
+
19
+ def message
20
+ "#{@reference} don't allow null"
21
+ end
22
+ end
23
+
24
+ class NotExistRequiredKey < StandardError
25
+ def initialize(keys, reference)
26
+ @keys = keys
27
+ @reference = reference
28
+ end
29
+
30
+ def message
31
+ "required parameters #{@keys.join(",")} not exist in #{@reference}"
32
+ end
33
+ end
34
+
35
+ class NotAnyOf < StandardError
36
+ def initialize(value, reference)
37
+ @value = value
38
+ @reference = reference
39
+ end
40
+
41
+ def message
42
+ "#{@value} isn't any of in #{@reference}"
43
+ end
44
+ end
45
+
46
+ class NotEnumInclude < StandardError
47
+ def initialize(value, reference)
48
+ @value = value
49
+ @reference = reference
50
+ end
51
+
52
+ def message
53
+ "#{@value} isn't include enum in #{@reference}"
54
+ end
55
+ end
56
+
57
+ class << self
58
+ # @param [Hash] value
59
+ # @param [OpenAPIParser::Schemas::Schema]
60
+ def validate(value, schema)
61
+ new(value, schema).validate_data
62
+ end
63
+ end
64
+
65
+ # @param [Hash] value
66
+ # @param [OpenAPIParser::Schemas::Schema] schema
67
+ def initialize(value, schema)
68
+ @value = value
69
+ @schema = schema
70
+ end
71
+
72
+ def validate_data
73
+ err = validate_schema(@value, @schema)
74
+ raise err if err
75
+ nil
76
+ end
77
+
78
+ private
79
+
80
+ # @param [Object] value
81
+ # @param [OpenAPIParser::Schemas::Schema] schema
82
+ def validate_schema(value, schema)
83
+ return unless schema
84
+ return validate_any_of(value, schema) if schema.any_of
85
+
86
+ if value.nil?
87
+ return if schema.nullable
88
+ return NotNullError.new(schema.object_reference)
89
+ end
90
+
91
+ case schema.type
92
+ when "string"
93
+ return validate_string(value, schema) if value.is_a?(String)
94
+ when "integer"
95
+ return validate_integer(value, schema) if value.is_a?(Integer)
96
+ when "boolean"
97
+ return if value.is_a?(TrueClass)
98
+ return if value.is_a?(FalseClass)
99
+ when "number"
100
+ return validate_integer(value, schema) if value.is_a?(Integer)
101
+ return validate_number(value, schema) if value.is_a?(Numeric)
102
+ when "object"
103
+ return validate_object(value, schema) if value.is_a?(Hash)
104
+ when "array"
105
+ return validate_array(value, schema) if value.is_a?(Array)
106
+ else
107
+ # TODO: unknown type support
108
+ end
109
+
110
+ ValidateError.new(value, schema.type, schema.object_reference)
111
+ end
112
+
113
+ # @param [Object] value
114
+ # @param [OpenAPIParser::Schemas::Schema] schema
115
+ def validate_any_of(value, schema)
116
+ # in all schema return error (=true) not any of data
117
+ schema.any_of.all? { |s| validate_schema(value, s) } ? NotAnyOf.new(value, schema.object_reference) : nil
118
+ end
119
+
120
+ def validate_string(value, schema)
121
+ check_enum_include(value, schema)
122
+ end
123
+
124
+ def validate_integer(value, schema)
125
+ check_enum_include(value, schema)
126
+ end
127
+
128
+ def validate_number(value, schema)
129
+ check_enum_include(value, schema)
130
+ end
131
+
132
+ # @param [Object] value
133
+ # @param [OpenAPIParser::Schemas::Schema] schema
134
+ def check_enum_include(value, schema)
135
+ return unless schema.enum
136
+ return if schema.enum.include?(value)
137
+
138
+ NotEnumInclude.new(value, schema.object_reference)
139
+ end
140
+
141
+ # @param [Hash] value
142
+ # @param [OpenAPIParser::Schemas::Schema] schema
143
+ def validate_object(value, schema)
144
+ return unless schema.properties
145
+ required_set = schema.required ? schema.required.to_set : Set.new
146
+
147
+ value.each do |name, v|
148
+ s = schema.properties[name]
149
+ err = validate_schema(v, s)
150
+ return err if err
151
+
152
+ required_set.delete(name)
153
+ end
154
+
155
+ return NotExistRequiredKey.new(required_set.to_a, schema.object_reference) unless required_set.empty?
156
+ nil
157
+ end
158
+
159
+ # @param [Array] value
160
+ # @param [OpenAPIParser::Schemas::Schema] schema
161
+ def validate_array(value, schema)
162
+ # array type have an schema in items property
163
+ items_schema = schema.items
164
+
165
+ value.each do |v|
166
+ err = validate_schema(v, items_schema)
167
+ return err if err
168
+ end
169
+
170
+ nil
171
+ end
172
+ end
@@ -0,0 +1,15 @@
1
+ require_relative 'schemas/classes'
2
+
3
+ require_relative 'schemas/base'
4
+ require_relative 'schemas/openapi'
5
+ require_relative 'schemas/paths'
6
+ require_relative 'schemas/path_item'
7
+ require_relative 'schemas/operation'
8
+ require_relative 'schemas/parameter'
9
+ require_relative 'schemas/reference'
10
+ require_relative 'schemas/request_body'
11
+ require_relative 'schemas/response'
12
+ require_relative 'schemas/responses'
13
+ require_relative 'schemas/components'
14
+ require_relative 'schemas/media_type'
15
+ require_relative 'schemas/schema'
@@ -0,0 +1,28 @@
1
+ module OpenAPIParser::Schemas
2
+ class Base
3
+ include OpenAPIParser::Parseable
4
+ include OpenAPIParser::Findable
5
+
6
+ attr_reader :parent, :raw_schema, :object_reference, :root
7
+
8
+ # @param [OpenAPIParser::Schemas::Base]
9
+ def initialize(object_reference, parent, root, raw_schema)
10
+ @raw_schema = raw_schema
11
+ @parent = parent
12
+ @root = root
13
+ @object_reference = object_reference
14
+
15
+ load_data
16
+ after_init
17
+ end
18
+
19
+ # override
20
+ def after_init
21
+
22
+ end
23
+
24
+ def inspect
25
+ @object_reference
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ # We want to use class name for DSL in class definition so we should define first...
2
+
3
+ module OpenAPIParser::Schemas
4
+ class Base; end
5
+ class OpenAPI < Base; end
6
+ class Operation < Base; end
7
+ class Parameter < Base; end
8
+ class PathItem < Base; end
9
+ class Paths < Base; end
10
+ class Reference < Base; end
11
+ class RequestBody < Base; end
12
+ class Responses < Base; end
13
+ class Response < Base; end
14
+ class MediaType < Base; end
15
+ class Schema < Base; end
16
+ class Components < Base; end
17
+ end
@@ -0,0 +1,25 @@
1
+ # TODO: examples
2
+ # TODO: headers
3
+ # TODO: securitySchemes
4
+ # TODO: links
5
+ # TODO: callbacks
6
+
7
+ module OpenAPIParser::Schemas
8
+ class Components < Base
9
+ # @!attribute [r] parameters
10
+ # @return [Hash{String => Parameter}, nil]
11
+ openapi_attr_hash_object :parameters, Parameter, reference: true
12
+
13
+ # @!attribute [r] parameters
14
+ # @return [Hash{String => Parameter}, nil]
15
+ openapi_attr_hash_object :schemas, Schema, reference: true
16
+
17
+ # @!attribute [r] responses
18
+ # @return [Hash{String => Response}, nil]
19
+ openapi_attr_hash_object :responses, Response, reference: true
20
+
21
+ # @!attribute [r] request_bodies
22
+ # @return [Hash{String => RequestBody}, nil]
23
+ openapi_attr_hash_object :request_bodies, RequestBody, reference: true, schema_key: :requestBodies
24
+ end
25
+ end
@@ -0,0 +1,16 @@
1
+ # TODO: example
2
+ # TODO: examples
3
+ # TODO: encoding
4
+
5
+ module OpenAPIParser::Schemas
6
+ class MediaType < Base
7
+ # @!attribute [r] schema
8
+ # @return [Schema, nil]
9
+ openapi_attr_object :schema, Schema, reference: true
10
+
11
+ # @param [Hash] params
12
+ def validate_parameter(params)
13
+ OpenAPIParser::SchemaValidator.validate(params, schema)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,31 @@
1
+ # TODO: info object
2
+ # TODO: servers object
3
+ # TODO: tags object
4
+ # TODO: externalDocs object
5
+
6
+ module OpenAPIParser::Schemas
7
+ class OpenAPI < Base
8
+ def initialize(raw_schema)
9
+ super('#', nil, self, raw_schema)
10
+ @find_object_cache = {}
11
+ @path_item_finder = OpenAPIParser::PathItemFinder.new(paths)
12
+ end
13
+
14
+ # @!attribute [r] openapi
15
+ # @return [String, nil]
16
+ openapi_attr_values :openapi
17
+
18
+ # @!attribute [r] paths
19
+ # @return [Paths, nil]
20
+ openapi_attr_object :paths, Paths, reference: false
21
+
22
+ # @!attribute [r] components
23
+ # @return [Components, nil]
24
+ openapi_attr_object :components, Components, reference: false
25
+
26
+ # @return [OpenAPIParser::RequestOperation]
27
+ def request_operation(http_method, request_path)
28
+ OpenAPIParser::RequestOperation.create(http_method, request_path, @path_item_finder)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,24 @@
1
+ # TODO: externalDocs
2
+ # TODO: callbacks
3
+ # TODO: security
4
+ # TODO: servers
5
+
6
+ module OpenAPIParser::Schemas
7
+ class Operation < Base
8
+ openapi_attr_values :tags, :summary, :description, :deprecated
9
+
10
+ openapi_attr_value :operation_id, schema_key: :operationId
11
+
12
+ openapi_attr_list_object :parameters, Parameter, reference: true
13
+
14
+ # @!attribute [r] request_body
15
+ # @return [OpenAPIParser::Schemas::RequestBody, nil]
16
+ openapi_attr_object :request_body, RequestBody, reference: true, schema_key: :requestBody
17
+
18
+ openapi_attr_object :responses, Responses, reference: false
19
+
20
+ def validate_request_body(content_type, params)
21
+ request_body&.validate_request_body(content_type, params)
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,12 @@
1
+ # TODO: support examples
2
+
3
+ module OpenAPIParser::Schemas
4
+ class Parameter < Base
5
+ openapi_attr_values :name, :in, :description, :required, :deprecated, :style, :explode, :example
6
+
7
+ openapi_attr_value :allow_empty_value, schema_key: :allowEmptyValue
8
+ openapi_attr_value :allow_reserved, schema_key: :allowReserved
9
+
10
+ openapi_attr_object :schema, Schema, reference: true
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ # TODO: support servers
2
+ # TODO: support reference
3
+
4
+ module OpenAPIParser::Schemas
5
+ class PathItem < Base
6
+ openapi_attr_values :summary, :description
7
+
8
+ openapi_attr_objects :get, :put, :post, :delete, :options, :head, :patch, :trace, Operation
9
+ openapi_attr_list_object :parameters, Parameter, reference: true
10
+
11
+ # @return [Operation]
12
+ def operation(method)
13
+ send(method)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,7 @@
1
+ module OpenAPIParser::Schemas
2
+ class Paths < Base
3
+ # @!attribute [r] path
4
+ # @return [Hash{String => PathItem, Reference}, nil]
5
+ openapi_attr_hash_body_objects 'path', PathItem, allow_reference: false, allow_data_type: false
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ module OpenAPIParser::Schemas
2
+ class Reference < Base
3
+ openapi_attr_value :ref, schema_key: '$ref'
4
+ end
5
+ end
@@ -0,0 +1,20 @@
1
+ # TODO: support extended property
2
+
3
+ module OpenAPIParser::Schemas
4
+ class RequestBody < Base
5
+ openapi_attr_values :description, :required
6
+
7
+ # @!attribute [r] content
8
+ # @return [Hash{String => MediaType}, nil]
9
+ openapi_attr_hash_object :content, MediaType, reference: false
10
+
11
+ def validate_request_body(_content_type, params)
12
+ # TODO: now support application/json only :(
13
+
14
+ media_type = content['application/json']
15
+ return nil unless media_type
16
+
17
+ media_type.validate_parameter(params)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,12 @@
1
+ # TODO: headers
2
+ # TODO: links
3
+
4
+ module OpenAPIParser::Schemas
5
+ class Response < Base
6
+ openapi_attr_values :description
7
+
8
+ # @!attribute [r] content
9
+ # @return [Hash{String => MediaType}, nil]
10
+ openapi_attr_hash_object :content, MediaType, reference: false
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ # TODO: support extended property
2
+
3
+ module OpenAPIParser::Schemas
4
+ class Responses < Base
5
+ # @!attribute [r] default
6
+ # @return [Response, Reference, nil]
7
+ openapi_attr_object :default, Response, reference: true
8
+
9
+ # @!attribute [r] response
10
+ # @return [Hash{String => Response, Reference}, nil]
11
+ openapi_attr_hash_body_objects 'response', Response, reject_keys: [:default], allow_reference: true, allow_data_type: false
12
+ end
13
+ end
@@ -0,0 +1,108 @@
1
+ # TODO: support 'not' because I need check reference...
2
+ # TODO: support 'discriminator', 'xml', 'externalDocs'
3
+ # TODO: support extended property
4
+
5
+ module OpenAPIParser::Schemas
6
+ class Schema < Base
7
+ # @!attribute [r] title
8
+ # @return [String, nil]
9
+ # @!attribute [r] pattern
10
+ # @return [String, nil] regexp
11
+ # @!attribute [r] pattern
12
+ # @return [String, nil] regexp
13
+ # @!attribute [r] description
14
+ # @return [String, nil]
15
+ # @!attribute [r] format
16
+ # @return [String, nil]
17
+ # @!attribute [r] type
18
+ # @return [String, nil] multiple types doesn't supported in OpenAPI3
19
+
20
+ # @!attribute [r] maximum
21
+ # @return [Float, nil]
22
+ # @!attribute [r] multipleOf
23
+ # @return [Float, nil]
24
+
25
+ # @!attribute [r] maxLength
26
+ # @return [Integer, nil]
27
+ # @!attribute [r] minLength
28
+ # @return [Integer, nil]
29
+ # @!attribute [r] maxItems
30
+ # @return [Integer, nil]
31
+ # @!attribute [r] minItems
32
+ # @return [Integer, nil]
33
+ # @!attribute [r] maxProperties
34
+ # @return [Integer, nil]
35
+ # @!attribute [r] minProperties
36
+ # @return [Integer, nil]
37
+
38
+ # @!attribute [r] exclusiveMaximum
39
+ # @return [Boolean, nil]
40
+ # @!attribute [r] exclusiveMinimum
41
+ # @return [Boolean, nil]
42
+ # @!attribute [r] uniqueItems
43
+ # @return [Boolean, nil]
44
+ # @!attribute [r] nullable
45
+ # @return [Boolean, nil]
46
+ # @!attribute [r] deprecated
47
+ # @return [Boolean, nil]
48
+
49
+ # @!attribute [r] required
50
+ # @return [Array<String>, nil] at least one item included
51
+
52
+ # @!attribute [r] enum
53
+ # @return [Array, nil] any type array
54
+
55
+ # @!attribute [r] default
56
+ # @return [Object, nil]
57
+
58
+ # @!attribute [r] example
59
+ # @return [Object, nil]
60
+
61
+ openapi_attr_values :title, :multipleOf,
62
+ :maximum, :exclusiveMaximum, :minimum, :exclusiveMinimum,
63
+ :maxLength, :minLength,
64
+ :pattern,
65
+ :maxItems, :minItems, :uniqueItems,
66
+ :maxProperties, :minProperties,
67
+ :required, :enum,
68
+ :description,
69
+ :format,
70
+ :default,
71
+ :type,
72
+ :nullable,
73
+ :example,
74
+ :deprecated
75
+
76
+ # @!attribute [r] read_only
77
+ # @return [Boolean, nil]
78
+ openapi_attr_value :read_only, schema_key: :readOnly
79
+
80
+ # @!attribute [r] write_only
81
+ # @return [Boolean, nil]
82
+ openapi_attr_value :write_only, schema_key: :writeOnly
83
+
84
+ # @!attribute [r] all_of
85
+ # @return [Array<Schema, Reference>, nil]
86
+ openapi_attr_list_object :all_of, Schema, reference: true, schema_key: :allOf
87
+
88
+ # @!attribute [r] one_of
89
+ # @return [Array<Schema, Reference>, nil]
90
+ openapi_attr_list_object :one_of, Schema, reference: true, schema_key: :oneOf
91
+
92
+ # @!attribute [r] any_of
93
+ # @return [Array<Schema, Reference>, nil]
94
+ openapi_attr_list_object :any_of, Schema, reference: true, schema_key: :anyOf
95
+
96
+ # @!attribute [r] items
97
+ # @return [Schema, nil]
98
+ openapi_attr_object :items, Schema, reference: true
99
+
100
+ # @!attribute [r] properties
101
+ # @return [Hash{String => Schema}, nil]
102
+ openapi_attr_hash_object :properties, Schema, reference: true
103
+
104
+ # @!attribute [r] additional_properties
105
+ # @return [Boolean, Schema, Reference, nil]
106
+ openapi_attr_object :additional_properties, Schema, reference: true, allow_data_type: true, schema_key: :additionalProperties
107
+ end
108
+ end
@@ -1,3 +1,3 @@
1
- module OpenapiParser
2
- VERSION = "0.1.0"
1
+ module OpenAPIParser
2
+ VERSION = '0.1.1'.freeze
3
3
  end
@@ -1,29 +1,31 @@
1
-
2
- lib = File.expand_path("../lib", __FILE__)
1
+ lib = File.expand_path('lib', __dir__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require "openapi_parser/version"
3
+ require 'openapi_parser/version'
5
4
 
6
5
  Gem::Specification.new do |spec|
7
- spec.name = "openapi_parser"
8
- spec.version = OpenapiParser::VERSION
9
- spec.authors = ["ota42y"]
10
- spec.email = ["ota42y@gmail.com"]
6
+ spec.name = 'openapi_parser'
7
+ spec.version = OpenAPIParser::VERSION
8
+ spec.authors = ['ota42y']
9
+ spec.email = ['ota42y@gmail.com']
11
10
 
12
- spec.summary = %q{OpenAPI3 parser}
13
- spec.description = %q{parser for OpenAPI 3.0 or later}
14
- spec.homepage = "https://ota42y.com"
15
- spec.license = "MIT"
11
+ spec.summary = 'OpenAPI3 parser'
12
+ spec.description = 'parser for OpenAPI 3.0 or later'
13
+ spec.homepage = 'https://github.com/ota42y/openapi_parser'
14
+ spec.license = 'MIT'
16
15
 
17
16
  # Specify which files should be added to the gem when it is released.
18
17
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
18
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
20
19
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
20
  end
22
- spec.bindir = "exe"
21
+ spec.bindir = 'exe'
23
22
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
- spec.require_paths = ["lib"]
23
+ spec.require_paths = ['lib']
25
24
 
26
- spec.add_development_dependency "bundler", "~> 1.16"
27
- spec.add_development_dependency "rake", "~> 10.0"
28
- spec.add_development_dependency "rspec", "~> 3.0"
25
+ spec.add_development_dependency 'bundler', '~> 1.16'
26
+ spec.add_development_dependency 'fincop'
27
+ spec.add_development_dependency 'rake', '~> 10.0'
28
+ spec.add_development_dependency 'rspec', '~> 3.0'
29
+ spec.add_development_dependency 'pry'
30
+ spec.add_development_dependency 'pry-byebug'
29
31
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openapi_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - ota42y
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-11-24 00:00:00.000000000 Z
11
+ date: 2018-12-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: fincop
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rake
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -52,6 +66,34 @@ dependencies:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
68
  version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry-byebug
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
55
97
  description: parser for OpenAPI 3.0 or later
56
98
  email:
57
99
  - ota42y@gmail.com
@@ -61,19 +103,40 @@ extra_rdoc_files: []
61
103
  files:
62
104
  - ".gitignore"
63
105
  - ".rspec"
106
+ - ".rubocop.yml"
64
107
  - ".travis.yml"
65
108
  - CODE_OF_CONDUCT.md
66
109
  - Gemfile
67
- - Gemfile.lock
68
110
  - LICENSE.txt
69
111
  - README.md
70
112
  - Rakefile
71
113
  - bin/console
72
114
  - bin/setup
73
115
  - lib/openapi_parser.rb
116
+ - lib/openapi_parser/concern.rb
117
+ - lib/openapi_parser/concerns/findable.rb
118
+ - lib/openapi_parser/concerns/parseable.rb
119
+ - lib/openapi_parser/path_item_finder.rb
120
+ - lib/openapi_parser/request_operation.rb
121
+ - lib/openapi_parser/schema_validator.rb
122
+ - lib/openapi_parser/schemas.rb
123
+ - lib/openapi_parser/schemas/base.rb
124
+ - lib/openapi_parser/schemas/classes.rb
125
+ - lib/openapi_parser/schemas/components.rb
126
+ - lib/openapi_parser/schemas/media_type.rb
127
+ - lib/openapi_parser/schemas/openapi.rb
128
+ - lib/openapi_parser/schemas/operation.rb
129
+ - lib/openapi_parser/schemas/parameter.rb
130
+ - lib/openapi_parser/schemas/path_item.rb
131
+ - lib/openapi_parser/schemas/paths.rb
132
+ - lib/openapi_parser/schemas/reference.rb
133
+ - lib/openapi_parser/schemas/request_body.rb
134
+ - lib/openapi_parser/schemas/response.rb
135
+ - lib/openapi_parser/schemas/responses.rb
136
+ - lib/openapi_parser/schemas/schema.rb
74
137
  - lib/openapi_parser/version.rb
75
138
  - openapi_parser.gemspec
76
- homepage: https://ota42y.com
139
+ homepage: https://github.com/ota42y/openapi_parser
77
140
  licenses:
78
141
  - MIT
79
142
  metadata: {}
data/Gemfile.lock DELETED
@@ -1,35 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- openapi_parser (0.1.0)
5
-
6
- GEM
7
- remote: https://rubygems.org/
8
- specs:
9
- diff-lcs (1.3)
10
- rake (10.5.0)
11
- rspec (3.8.0)
12
- rspec-core (~> 3.8.0)
13
- rspec-expectations (~> 3.8.0)
14
- rspec-mocks (~> 3.8.0)
15
- rspec-core (3.8.0)
16
- rspec-support (~> 3.8.0)
17
- rspec-expectations (3.8.2)
18
- diff-lcs (>= 1.2.0, < 2.0)
19
- rspec-support (~> 3.8.0)
20
- rspec-mocks (3.8.0)
21
- diff-lcs (>= 1.2.0, < 2.0)
22
- rspec-support (~> 3.8.0)
23
- rspec-support (3.8.0)
24
-
25
- PLATFORMS
26
- ruby
27
-
28
- DEPENDENCIES
29
- bundler (~> 1.16)
30
- openapi_parser!
31
- rake (~> 10.0)
32
- rspec (~> 3.0)
33
-
34
- BUNDLED WITH
35
- 1.16.6