openapi_parser 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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