openapi_parser 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +5 -2
  3. data/.rubocop_ignore.yml +6 -0
  4. data/.travis.yml +33 -4
  5. data/CHANGELOG.md +9 -0
  6. data/README.md +39 -6
  7. data/lib/openapi_parser/concern.rb +2 -1
  8. data/lib/openapi_parser/concerns/expandable.rb +52 -44
  9. data/lib/openapi_parser/concerns/media_type_selectable.rb +26 -0
  10. data/lib/openapi_parser/concerns/parser.rb +43 -0
  11. data/lib/openapi_parser/concerns/parser/core.rb +21 -0
  12. data/lib/openapi_parser/concerns/parser/hash.rb +10 -0
  13. data/lib/openapi_parser/concerns/parser/hash_body.rb +12 -0
  14. data/lib/openapi_parser/concerns/parser/list.rb +10 -0
  15. data/lib/openapi_parser/concerns/parser/object.rb +14 -0
  16. data/lib/openapi_parser/concerns/parser/value.rb +14 -0
  17. data/lib/openapi_parser/concerns/schema_loader.rb +58 -0
  18. data/lib/openapi_parser/concerns/schema_loader/base.rb +28 -0
  19. data/lib/openapi_parser/concerns/schema_loader/creator.rb +48 -0
  20. data/lib/openapi_parser/concerns/schema_loader/hash_body_loader.rb +37 -0
  21. data/lib/openapi_parser/concerns/schema_loader/hash_objects_loader.rb +29 -0
  22. data/lib/openapi_parser/concerns/schema_loader/list_loader.rb +28 -0
  23. data/lib/openapi_parser/concerns/schema_loader/objects_loader.rb +21 -0
  24. data/lib/openapi_parser/concerns/schema_loader/values_loader.rb +10 -0
  25. data/lib/openapi_parser/config.rb +1 -1
  26. data/lib/openapi_parser/errors.rb +9 -0
  27. data/lib/openapi_parser/path_item_finder.rb +18 -18
  28. data/lib/openapi_parser/request_operation.rb +4 -4
  29. data/lib/openapi_parser/schema_validator.rb +77 -54
  30. data/lib/openapi_parser/schema_validators/all_of_validator.rb +16 -0
  31. data/lib/openapi_parser/schema_validators/any_of_validator.rb +1 -1
  32. data/lib/openapi_parser/schema_validators/array_validator.rb +2 -4
  33. data/lib/openapi_parser/schema_validators/base.rb +9 -6
  34. data/lib/openapi_parser/schema_validators/boolean_validator.rb +11 -9
  35. data/lib/openapi_parser/schema_validators/float_validator.rb +8 -10
  36. data/lib/openapi_parser/schema_validators/integer_validator.rb +11 -10
  37. data/lib/openapi_parser/schema_validators/nil_validator.rb +1 -0
  38. data/lib/openapi_parser/schema_validators/object_validator.rb +3 -3
  39. data/lib/openapi_parser/schema_validators/string_validator.rb +13 -13
  40. data/lib/openapi_parser/schemas/base.rb +1 -2
  41. data/lib/openapi_parser/schemas/media_type.rb +3 -1
  42. data/lib/openapi_parser/schemas/openapi.rb +1 -1
  43. data/lib/openapi_parser/schemas/operation.rb +17 -14
  44. data/lib/openapi_parser/schemas/parameter.rb +2 -2
  45. data/lib/openapi_parser/schemas/request_body.rb +12 -5
  46. data/lib/openapi_parser/schemas/response.rb +4 -4
  47. data/lib/openapi_parser/schemas/responses.rb +21 -3
  48. data/lib/openapi_parser/version.rb +1 -1
  49. data/openapi_parser.gemspec +3 -2
  50. metadata +51 -19
  51. data/lib/openapi_parser/concerns/parseable.rb +0 -238
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1635ca728b8c31ce02b997acea2b7fb763b15558a785b17e95ca2ee47fe58232
4
- data.tar.gz: ff8c1957b980f7f363f7e68e44098e862996c73d140b57a9e02d0b39c4527a77
3
+ metadata.gz: e0035d4ece30f151226f04a1462ae6cf4d54c36011b315810bd49588f66b0632
4
+ data.tar.gz: cae26e5b18e0ab71b2027d56a828cccd737126852b96c68facf88f8ba27db0ab
5
5
  SHA512:
6
- metadata.gz: b39a5c07adaed7a98b0ed984767cf6bf0c92d6e8261f1cd94ddc4fe5598b0277c990b30901ed03eabbce638a434d2a8d78c9be18d1eaaac95805604929a57d8f
7
- data.tar.gz: 2e99c3ae918a2f1c4bc07e66ec71dddf877dda8457ded288aa744449806c02eae38d82c6c47782503fa3bec91b18bb5757605febfdd591ada31d24ebe94524f1
6
+ metadata.gz: 0456ee6d9363ff05c1ef517cbc9aa8cfbcad55aa054e012009ec685a5b97c7779c897842918a868dae3acefa143bbfa7790fc7bb1ba370e04293fc7ead130ef4
7
+ data.tar.gz: d2855d0574bfdc5a769576ffa89af5d1006f960af4a4790e92edfbe5763eb3a954698f71522d599524b1b9d906f11632440167c4e37e524435804873aeede533
@@ -1,10 +1,13 @@
1
1
  inherit_gem:
2
2
  fincop:
3
- - 'config/rails.yml'
3
+ # - 'config/rails.yml'
4
4
  - 'config/rspec.yml'
5
5
  - 'config/rubocop.yml'
6
- # If you are using Rails 4, activate this cop.
6
+ # If you are using Rails 4, activate this cop.
7
7
  # - 'config/disabled_for_rails_4.yml'
8
8
 
9
+ inherit_from:
10
+ - '.rubocop_ignore.yml'
11
+
9
12
  AllCops:
10
13
  TargetRubyVersion: 2.5
@@ -0,0 +1,6 @@
1
+ Metrics/ParameterLists:
2
+ Exclude:
3
+ - lib/openapi_parser/concerns/parser.rb
4
+
5
+ RSpec/FilePath:
6
+ Enabled: false
@@ -1,7 +1,36 @@
1
- ---
2
- sudo: false
1
+ env:
2
+ global:
3
+ - CC_TEST_REPORTER_ID=b49a1717b8ff0aef9eced41d0f87d350a88b46d55083ba2e3df8b6f441ae3fb7
4
+
3
5
  language: ruby
4
- cache: bundler
6
+
5
7
  rvm:
8
+ - 2.3.8
9
+ - 2.4.5
6
10
  - 2.5.3
7
- before_install: gem install bundler -v 1.16.6
11
+ - 2.6.0
12
+ - ruby-head
13
+
14
+ cache: bundler
15
+
16
+ before_script:
17
+ - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
18
+ - chmod +x ./cc-test-reporter
19
+ - ./cc-test-reporter before-build
20
+
21
+ script: bundle exec rspec
22
+
23
+ after_script:
24
+ - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
25
+
26
+ notifications:
27
+ email: false
28
+
29
+ sudo: false
30
+
31
+ git:
32
+ depth: 10
33
+
34
+ matrix:
35
+ allow_failures:
36
+ - rvm: ruby-head
@@ -0,0 +1,9 @@
1
+ ## Unreleased
2
+
3
+ ## 0.1.6 (2018-12-29)
4
+ * Support allOf definition (#11)
5
+ * Support wildcard status code (#12)
6
+ * Support wildcard content type (#13)
7
+
8
+ ## 0.1.5 (2018-12-23)
9
+ * First release for production usage
data/README.md CHANGED
@@ -1,8 +1,41 @@
1
1
  # OpenAPI Parser
2
+ [![Build Status](https://travis-ci.org/ota42y/openapi_parser.svg?branch=master)](https://travis-ci.org/ota42y/openapi_parser)
3
+ [![Gem Version](https://badge.fury.io/rb/openapi_parser.svg)](https://badge.fury.io/rb/openapi_parser)
4
+ [![Yard Docs](https://img.shields.io/badge/yard-docs-blue.svg)](https://www.rubydoc.info/gems/openapi_parser)
5
+ [![Maintainability](https://api.codeclimate.com/v1/badges/62bad4bcb3f691d46487/maintainability)](https://codeclimate.com/github/ota42y/openapi_parser/maintainability)
6
+ [![Test Coverage](https://api.codeclimate.com/v1/badges/62bad4bcb3f691d46487/test_coverage)](https://codeclimate.com/github/ota42y/openapi_parser/test_coverage)
7
+ [![Inch CI](https://inch-ci.org/github/ota42y/openapi_parser.svg?branch=master)](https://inch-ci.org/github/ota42y/openapi_parser)
2
8
 
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.
9
+ This is OpenAPI3 parser and validator.
4
10
 
5
- TODO: Delete this and the text above, and describe your gem
11
+ ## Usage
12
+
13
+ ```ruby
14
+ root = OpenAPIParser.parse(YAML.load_file('open_api_3/schema.yml'))
15
+
16
+ # request operation combine path parameters and OpenAPI3's Operation Object
17
+ request_operation = root.request_operation(:post, '/validate')
18
+
19
+ ret = request_operation.validate_request_body('application/json', {"integer" => 1})
20
+ # => {"integer" => 1}
21
+
22
+ # invalid parameter
23
+ request_operation.validate_request_body('application/json', {"integer" => '1'})
24
+ # => OpenAPIParser::ValidateError: 1 class is String but it's not valid integer in #/paths/~1validate/post/requestBody/content/application~1json/schema/properties/integer
25
+
26
+ # path parameter
27
+ request_operation = root.request_operation(:get, '/path_template_test/1')
28
+ request_operation.path_params
29
+ # => {"template_name"=>"1"}
30
+
31
+ # coerce parameter
32
+ root = OpenAPIParser.parse(YAML.load_file('open_api_3/schema.yml'), {coerce_value: true, datetime_coerce_class: DateTime})
33
+ request_operation = root.request_operation(:get, '/string_params_coercer')
34
+ request_operation.validate_request_parameter({'integer_1' => '1', 'datetime_string' => '2016-04-01T16:00:00+09:00'})
35
+ # => {"integer_1"=>1, "datetime_string"=>#<DateTime: 2016-04-01T16:00:00+09:00 ((2457480j,25200s,0n),+32400s,2299161j)>
36
+ # convert number string to Integer and datetime string to DateTime class
37
+
38
+ ```
6
39
 
7
40
  ## Installation
8
41
 
@@ -20,9 +53,9 @@ Or install it yourself as:
20
53
 
21
54
  $ gem install openapi_parser
22
55
 
23
- ## Usage
24
-
25
- TODO: Write usage instructions here
56
+ ## ToDo
57
+ - correct schema checker
58
+ - more detailed validator
26
59
 
27
60
  ## Development
28
61
 
@@ -32,7 +65,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
32
65
 
33
66
  ## Contributing
34
67
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/openapi_parser. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
68
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ota42y/openapi_parser. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
36
69
 
37
70
  ## License
38
71
 
@@ -1,3 +1,4 @@
1
- require_relative 'concerns/parseable'
1
+ require_relative 'concerns/parser'
2
2
  require_relative 'concerns/findable'
3
3
  require_relative 'concerns/expandable'
4
+ require_relative 'concerns/media_type_selectable'
@@ -1,25 +1,30 @@
1
1
  module OpenAPIParser::Expandable
2
+ # expand refs
3
+ # @param [OpenAPIParser::Schemas::Base] root
4
+ # @return nil
2
5
  def expand_reference(root)
3
- expand_list_objects(root, self.class._openapi_attr_list_objects&.keys)
4
- expand_objects(root, self.class._openapi_attr_objects&.keys)
5
- expand_hash_objects(root, self.class._openapi_attr_hash_objects&.keys)
6
- expand_hash_objects(root, self.class._openapi_attr_hash_body_objects&.keys)
6
+ expand_list_objects(root, self.class._openapi_attr_list_objects.keys)
7
+ expand_objects(root, self.class._openapi_attr_objects.keys)
8
+ expand_hash_objects(root, self.class._openapi_attr_hash_objects.keys)
9
+ expand_hash_objects(root, self.class._openapi_attr_hash_body_objects.keys)
10
+ nil
7
11
  end
8
12
 
9
13
  private
10
14
 
11
- def expand_hash_objects(root, attribute_names)
12
- return unless attribute_names
15
+ def expand_hash_objects(root, attribute_names)
16
+ return unless attribute_names
13
17
 
14
- attribute_names.each do |name|
18
+ attribute_names.each { |name| expand_hash_attribute(root, name) }
19
+ end
20
+
21
+ def expand_hash_attribute(root, name)
15
22
  h = send(name)
16
- next if h.nil?
23
+ return if h.nil?
17
24
 
18
25
  update_values = h.map do |k, v|
19
- next [k, referenced_object(root, v)] if v.is_a?(OpenAPIParser::Schemas::Reference)
20
- v.expand_reference(root) if v.is_a?(OpenAPIParser::Expandable)
21
-
22
- nil
26
+ new_object = expand_object(root, v)
27
+ new_object.nil? ? nil : [k, new_object]
23
28
  end
24
29
 
25
30
  update_values.compact.each do |k, v|
@@ -27,50 +32,53 @@ module OpenAPIParser::Expandable
27
32
  h[k] = v
28
33
  end
29
34
  end
30
- end
31
35
 
32
- def expand_objects(root, attribute_names)
33
- return unless attribute_names
36
+ def expand_objects(root, attribute_names)
37
+ return unless attribute_names
34
38
 
35
- attribute_names.each do |name|
36
- v = send(name)
37
- next if v.nil?
39
+ attribute_names.each do |name|
40
+ v = send(name)
41
+ next if v.nil?
38
42
 
39
- if v.is_a?(OpenAPIParser::Schemas::Reference)
40
- obj = referenced_object(root, v)
41
- _update_child_object(v, obj)
42
- self.instance_variable_set("@#{name}", obj)
43
- elsif v.is_a?(OpenAPIParser::Expandable)
44
- v.expand_reference(root)
43
+ new_object = expand_object(root, v)
44
+ next if new_object.nil?
45
+
46
+ _update_child_object(v, new_object)
47
+ self.instance_variable_set("@#{name}", new_object)
45
48
  end
46
49
  end
47
- end
48
50
 
49
- def expand_list_objects(root, attribute_names)
50
- return unless attribute_names
51
+ def expand_list_objects(root, attribute_names)
52
+ return unless attribute_names
53
+
54
+ attribute_names.each do |name|
55
+ l = send(name)
56
+ next if l.nil?
51
57
 
52
- attribute_names.each do |name|
53
- l = send(name)
54
- next if l.nil?
58
+ l.each_with_index do |v, idx|
59
+ new_object = expand_object(root, v)
60
+ next if new_object.nil?
55
61
 
56
- l.each_with_index do |v, idx|
57
- if v.is_a?(OpenAPIParser::Schemas::Reference)
58
- obj = referenced_object(root, v)
59
- _update_child_object(v, obj)
60
- l[idx] = obj
61
- elsif v.is_a?(OpenAPIParser::Expandable)
62
- v.expand_reference(root)
62
+ _update_child_object(v, new_object)
63
+ l[idx] = new_object
63
64
  end
64
65
  end
65
66
  end
66
- end
67
67
 
68
+ def expand_object(root, object)
69
+ if object.kind_of?(OpenAPIParser::Schemas::Reference)
70
+ return referenced_object(root, object)
71
+ end
72
+
73
+ object.expand_reference(root) if object.kind_of?(OpenAPIParser::Expandable)
74
+ nil
75
+ end
68
76
 
69
- # @param [OpenAPIParser::Schemas::OpenAPI] root
70
- # @param [OpenAPIParser::Schemas::Reference] reference
71
- def referenced_object(root, reference)
72
- obj = root.find_object(reference.ref)
77
+ # @param [OpenAPIParser::Schemas::OpenAPI] root
78
+ # @param [OpenAPIParser::Schemas::Reference] reference
79
+ def referenced_object(root, reference)
80
+ obj = root.find_object(reference.ref)
73
81
 
74
- obj.is_a?(OpenAPIParser::Schemas::Reference) ? referenced_object(root, obj) : obj
75
- end
82
+ obj.kind_of?(OpenAPIParser::Schemas::Reference) ? referenced_object(root, obj) : obj
83
+ end
76
84
  end
@@ -0,0 +1,26 @@
1
+ module OpenAPIParser::MediaTypeSelectable
2
+ # select media type by content_type (consider wild card definition)
3
+ # @param [String] content_type
4
+ # @param [Hash{String => OpenAPIParser::Schemas::MediaType}] content
5
+ # @return [OpenAPIParser::Schemas::MediaType, nil]
6
+ def select_media_type(content_type, content)
7
+ return nil unless content_type
8
+
9
+ if (media_type = content[content_type])
10
+ return media_type
11
+ end
12
+
13
+ # application/json => [application, json]
14
+ splited = content_type.split('/')
15
+
16
+ if (media_type = content["#{splited.first}/*"])
17
+ return media_type
18
+ end
19
+
20
+ if (media_type = content['*/*'])
21
+ return media_type
22
+ end
23
+
24
+ nil
25
+ end
26
+ end
@@ -0,0 +1,43 @@
1
+ module OpenAPIParser::Parser
2
+ end
3
+
4
+ require_relative './parser/core'
5
+ require_relative './schema_loader'
6
+
7
+ module OpenAPIParser::Parser
8
+ def self.included(base)
9
+ base.extend(ClassMethods)
10
+ end
11
+ module ClassMethods
12
+ extend Forwardable
13
+
14
+ def_delegators :_parser_core, :_openapi_attr_values, :openapi_attr_value, :openapi_attr_values
15
+ def_delegators :_parser_core, :_openapi_attr_objects, :openapi_attr_objects, :openapi_attr_object
16
+ def_delegators :_parser_core, :_openapi_attr_list_objects, :openapi_attr_list_object
17
+ def_delegators :_parser_core, :_openapi_attr_hash_objects, :openapi_attr_hash_object
18
+ def_delegators :_parser_core, :_openapi_attr_hash_body_objects, :openapi_attr_hash_body_objects
19
+
20
+ def _parser_core
21
+ @_parser_core ||= OpenAPIParser::Parser::Core.new(self)
22
+ end
23
+ end
24
+
25
+ # @param [OpenAPIParser::Schemas::Base] old
26
+ # @param [OpenAPIParser::Schemas::Base] new
27
+ def _update_child_object(old, new)
28
+ _openapi_all_child_objects[old.object_reference] = new
29
+ end
30
+
31
+ # @return [Hash{String => OpenAPIParser::Schemas::Base}]
32
+ def _openapi_all_child_objects
33
+ @_openapi_all_child_objects ||= {}
34
+ end
35
+
36
+ # load data by schema definition in core and set children to _openapi_all_child_objects
37
+ # @return nil
38
+ def load_data
39
+ loader = ::OpenAPIParser::SchemaLoader.new(self, self.class._parser_core)
40
+ @_openapi_all_child_objects = loader.load_data
41
+ nil
42
+ end
43
+ end
@@ -0,0 +1,21 @@
1
+ require_relative './value'
2
+ require_relative './object'
3
+ require_relative './list'
4
+ require_relative './hash'
5
+ require_relative './hash_body'
6
+
7
+ class OpenAPIParser::Parser::Core
8
+ include OpenAPIParser::Parser::Value
9
+ include OpenAPIParser::Parser::Object
10
+ include OpenAPIParser::Parser::List
11
+ include OpenAPIParser::Parser::Hash
12
+ include OpenAPIParser::Parser::HashBody
13
+
14
+ def initialize(target_klass)
15
+ @target_klass = target_klass
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :target_klass
21
+ end
@@ -0,0 +1,10 @@
1
+ module OpenAPIParser::Parser::Hash
2
+ def _openapi_attr_hash_objects
3
+ @_openapi_attr_hash_objects ||= {}
4
+ end
5
+
6
+ def openapi_attr_hash_object(name, klass, options = {})
7
+ target_klass.send(:attr_reader, name)
8
+ _openapi_attr_hash_objects[name] = ::OpenAPIParser::SchemaLoader::HashObjectsLoader.new(name, options.merge(klass: klass))
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ module OpenAPIParser::Parser::HashBody
2
+ def _openapi_attr_hash_body_objects
3
+ @_openapi_attr_hash_body_objects ||= {}
4
+ end
5
+
6
+ def openapi_attr_hash_body_objects(name, klass, options = {})
7
+ #options[:reject_keys] = options[:reject_keys] ? options[:reject_keys].map(&:to_s) : []
8
+
9
+ target_klass.send(:attr_reader, name)
10
+ _openapi_attr_hash_body_objects[name] = ::OpenAPIParser::SchemaLoader::HashBodyLoader.new(name, options.merge(klass: klass))
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ module OpenAPIParser::Parser::List
2
+ def _openapi_attr_list_objects
3
+ @_openapi_attr_list_objects ||= {}
4
+ end
5
+
6
+ def openapi_attr_list_object(name, klass, options = {})
7
+ target_klass.send(:attr_reader, name)
8
+ _openapi_attr_list_objects[name] = OpenAPIParser::SchemaLoader::ListLoader.new(name, options.merge(klass: klass))
9
+ end
10
+ end
@@ -0,0 +1,14 @@
1
+ module OpenAPIParser::Parser::Object
2
+ def _openapi_attr_objects
3
+ @_openapi_attr_objects ||= {}
4
+ end
5
+
6
+ def openapi_attr_objects(*names, klass)
7
+ names.each { |name| openapi_attr_object(name, klass) }
8
+ end
9
+
10
+ def openapi_attr_object(name, klass, options = {})
11
+ target_klass.send(:attr_reader, name)
12
+ _openapi_attr_objects[name] = OpenAPIParser::SchemaLoader::ObjectsLoader.new(name, options.merge(klass: klass))
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module OpenAPIParser::Parser::Value
2
+ def _openapi_attr_values
3
+ @_openapi_attr_values ||= {}
4
+ end
5
+
6
+ def openapi_attr_values(*names)
7
+ names.each { |name| openapi_attr_value(name) }
8
+ end
9
+
10
+ def openapi_attr_value(name, options = {})
11
+ target_klass.send(:attr_reader, name)
12
+ _openapi_attr_values[name] = OpenAPIParser::SchemaLoader::ValuesLoader.new(name, options)
13
+ end
14
+ end