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
@@ -0,0 +1,16 @@
1
+ # validate AllOf schema
2
+ class OpenAPIParser::SchemaValidator
3
+ class AllOfValidator < Base
4
+ # coerce and validate value
5
+ # @param [Object] value
6
+ # @param [OpenAPIParser::Schemas::Schema] schema
7
+ def coerce_and_validate(value, schema)
8
+ # if any schema return error, it's not valida all of value
9
+ schema.all_of.each do |s|
10
+ _coerced, err = validatable.validate_schema(value, s)
11
+ return [nil, err] if err
12
+ end
13
+ [value, nil]
14
+ end
15
+ end
16
+ end
@@ -5,7 +5,7 @@ class OpenAPIParser::SchemaValidator
5
5
  def coerce_and_validate(value, schema)
6
6
  # in all schema return error (=true) not any of data
7
7
  schema.any_of.each do |s|
8
- coerced, err = validator.validate_schema(value, s)
8
+ coerced, err = validatable.validate_schema(value, s)
9
9
  return [coerced, nil] if err.nil?
10
10
  end
11
11
  [nil, OpenAPIParser::NotAnyOf.new(value, schema.object_reference)]
@@ -1,17 +1,15 @@
1
1
  class OpenAPIParser::SchemaValidator
2
2
  class ArrayValidator < Base
3
-
4
3
  # @param [Array] value
5
4
  # @param [OpenAPIParser::Schemas::Schema] schema
6
5
  def coerce_and_validate(value, schema)
7
- return validator.validate_error(value, schema) unless value.is_a?(Array)
6
+ return OpenAPIParser::ValidateError.build_error_result(value, schema) unless value.kind_of?(Array)
8
7
 
9
8
  # array type have an schema in items property
10
9
  items_schema = schema.items
11
10
 
12
-
13
11
  coerced_values = value.map do |v|
14
- coerced, err = validator.validate_schema(v, items_schema)
12
+ coerced, err = validatable.validate_schema(v, items_schema)
15
13
  return [nil, err] if err
16
14
 
17
15
  coerced
@@ -1,16 +1,19 @@
1
1
  class OpenAPIParser::SchemaValidator
2
2
  class Base
3
- def initialize(validator, coerce_value)
4
- @validator = validator
3
+ # @param [OpenAPIParser::SchemaValidator::Validatable] validatable
4
+ def initialize(validatable, coerce_value)
5
+ @validatable = validatable
5
6
  @coerce_value = coerce_value
6
7
  end
7
8
 
8
- attr_reader :validator
9
+ attr_reader :validatable
9
10
 
10
- # @!attribute [r] validator
11
- # @return [OpenAPIParser::SchemaValidator]
11
+ # @!attribute [r] validatable
12
+ # @return [OpenAPIParser::SchemaValidator::Validatable]
12
13
 
13
- # return [coerced_value, error]
14
+ # need override
15
+ # @param [Array] _value
16
+ # @param [OpenAPIParser::Schemas::Schema] _schema
14
17
  def coerce_and_validate(_value, _schema)
15
18
  raise 'need implement'
16
19
  end
@@ -1,22 +1,24 @@
1
1
  class OpenAPIParser::SchemaValidator
2
2
  class BooleanValidator < Base
3
+ TRUE_VALUES = ['true', '1'].freeze
4
+ FALSE_VALUES = ['false', '0'].freeze
5
+
3
6
  def coerce_and_validate(value, schema)
4
7
  value = coerce(value) if @coerce_value
5
8
 
6
- return validator.validate_error(value, schema) unless value.is_a?(TrueClass) || value.is_a?(FalseClass)
9
+ return OpenAPIParser::ValidateError.build_error_result(value, schema) unless value.kind_of?(TrueClass) || value.kind_of?(FalseClass)
10
+
7
11
  [value, nil]
8
12
  end
9
13
 
10
14
  private
11
15
 
12
- def coerce(value)
13
- if value == "true" || value == "1"
14
- return true
15
- end
16
- if value == "false" || value == "0"
17
- return false
16
+ def coerce(value)
17
+ return true if TRUE_VALUES.include?(value)
18
+
19
+ return false if FALSE_VALUES.include?(value)
20
+
21
+ value
18
22
  end
19
- value
20
- end
21
23
  end
22
24
  end
@@ -5,25 +5,23 @@ class OpenAPIParser::SchemaValidator
5
5
  def coerce_and_validate(value, schema)
6
6
  value = coerce(value) if @coerce_value
7
7
 
8
- return validator.validate_integer(value, schema) if value.is_a?(Integer)
8
+ return OpenAPIParser::ValidateError.build_error_result(value, schema) if value.kind_of?(Integer)
9
+
9
10
  coercer_and_validate_numeric(value, schema)
10
11
  end
11
12
 
12
13
  private
13
14
 
14
- def coercer_and_validate_numeric(value, schema)
15
- return validator.validate_error(value, schema) unless value.is_a?(Numeric)
16
- check_enum_include(value, schema)
17
- end
15
+ def coercer_and_validate_numeric(value, schema)
16
+ return OpenAPIParser::ValidateError.build_error_result(value, schema) unless value.kind_of?(Numeric)
18
17
 
19
- private
18
+ check_enum_include(value, schema)
19
+ end
20
20
 
21
- def coerce(value)
22
- begin
23
- return Float(value)
21
+ def coerce(value)
22
+ Float(value)
24
23
  rescue ArgumentError => e
25
24
  raise e unless e.message =~ /invalid value for Float/
26
25
  end
27
- end
28
26
  end
29
27
  end
@@ -5,22 +5,23 @@ class OpenAPIParser::SchemaValidator
5
5
  def coerce_and_validate(value, schema)
6
6
  value = coerce(value) if @coerce_value
7
7
 
8
- return validator.validate_error(value, schema) unless value.is_a?(Integer)
8
+ return OpenAPIParser::ValidateError.build_error_result(value, schema) unless value.kind_of?(Integer)
9
+
9
10
  check_enum_include(value, schema)
10
11
  end
11
12
 
12
13
  private
13
14
 
14
- def coerce(value)
15
- return value if value.is_a?(Integer)
15
+ def coerce(value)
16
+ return value if value.kind_of?(Integer)
16
17
 
17
- begin
18
- return Integer(value)
19
- rescue ArgumentError => e
20
- raise e unless e.message =~ /invalid value for Integer/
21
- end
18
+ begin
19
+ return Integer(value)
20
+ rescue ArgumentError => e
21
+ raise e unless e.message =~ /invalid value for Integer/
22
+ end
22
23
 
23
- value
24
- end
24
+ value
25
+ end
25
26
  end
26
27
  end
@@ -4,6 +4,7 @@ class OpenAPIParser::SchemaValidator
4
4
  # @param [OpenAPIParser::Schemas::Schema] schema
5
5
  def coerce_and_validate(value, schema)
6
6
  return [value, nil] if schema.nullable
7
+
7
8
  [nil, OpenAPIParser::NotNullError.new(schema.object_reference)]
8
9
  end
9
10
  end
@@ -1,17 +1,17 @@
1
1
  class OpenAPIParser::SchemaValidator
2
2
  class ObjectValidator < Base
3
-
4
3
  # @param [Hash] value
5
4
  # @param [OpenAPIParser::Schemas::Schema] schema
6
5
  def coerce_and_validate(value, schema)
7
- return validator.validate_error(value, schema) unless value.is_a?(Hash)
6
+ return OpenAPIParser::ValidateError.build_error_result(value, schema) unless value.kind_of?(Hash)
8
7
 
9
8
  return [value, nil] unless schema.properties
9
+
10
10
  required_set = schema.required ? schema.required.to_set : Set.new
11
11
 
12
12
  coerced_values = value.map do |name, v|
13
13
  s = schema.properties[name]
14
- coerced, err = validator.validate_schema(v, s)
14
+ coerced, err = validatable.validate_schema(v, s)
15
15
  return [nil, err] if err
16
16
 
17
17
  required_set.delete(name)
@@ -8,7 +8,7 @@ class OpenAPIParser::SchemaValidator
8
8
  end
9
9
 
10
10
  def coerce_and_validate(value, schema)
11
- return validator.validate_error(value, schema) unless value.is_a?(String)
11
+ return OpenAPIParser::ValidateError.build_error_result(value, schema) unless value.kind_of?(String)
12
12
 
13
13
  value, err = check_enum_include(value, schema)
14
14
  return [nil, err] if err
@@ -20,19 +20,19 @@ class OpenAPIParser::SchemaValidator
20
20
 
21
21
  private
22
22
 
23
- # @param [OpenAPIParser::Schemas::Schema] schema
24
- def coerce_date_time(value, schema)
25
- schema.format == "date-time" ? parse_date_time(value) : value
26
- end
27
-
28
- def parse_date_time(value)
29
- begin
30
- return @datetime_coerce_class.parse(value)
31
- rescue ArgumentError => e
32
- raise e unless e.message =~ /invalid date/
23
+ # @param [OpenAPIParser::Schemas::Schema] schema
24
+ def coerce_date_time(value, schema)
25
+ (schema.format == 'date-time') ? parse_date_time(value) : value
33
26
  end
34
27
 
35
- value
36
- end
28
+ def parse_date_time(value)
29
+ begin
30
+ return @datetime_coerce_class.parse(value)
31
+ rescue ArgumentError => e
32
+ raise e unless e.message =~ /invalid date/
33
+ end
34
+
35
+ value
36
+ end
37
37
  end
38
38
  end
@@ -1,6 +1,6 @@
1
1
  module OpenAPIParser::Schemas
2
2
  class Base
3
- include OpenAPIParser::Parseable
3
+ include OpenAPIParser::Parser
4
4
  include OpenAPIParser::Findable
5
5
  include OpenAPIParser::Expandable
6
6
 
@@ -19,7 +19,6 @@ module OpenAPIParser::Schemas
19
19
 
20
20
  # override
21
21
  def after_init
22
-
23
22
  end
24
23
 
25
24
  def inspect
@@ -5,10 +5,12 @@
5
5
  module OpenAPIParser::Schemas
6
6
  class MediaType < Base
7
7
  # @!attribute [r] schema
8
- # @return [Schema, nil]
8
+ # @return [Schema, nil] OpenAPI3 Schema object
9
9
  openapi_attr_object :schema, Schema, reference: true
10
10
 
11
+ # validate params by schema definitions
11
12
  # @param [Hash] params
13
+ # @param [OpenAPIParser::SchemaValidator::Options] options
12
14
  def validate_parameter(params, options)
13
15
  OpenAPIParser::SchemaValidator.validate(params, schema, options)
14
16
  end
@@ -8,7 +8,7 @@ module OpenAPIParser::Schemas
8
8
  def initialize(raw_schema, config)
9
9
  super('#', nil, self, raw_schema)
10
10
  @find_object_cache = {}
11
- @path_item_finder = OpenAPIParser::PathItemFinder.new(paths)
11
+ @path_item_finder = OpenAPIParser::PathItemFinder.new(paths) if paths # invalid definition
12
12
  @config = config
13
13
  end
14
14
 
@@ -12,15 +12,18 @@ module OpenAPIParser::Schemas
12
12
  openapi_attr_list_object :parameters, Parameter, reference: true
13
13
 
14
14
  # @!attribute [r] request_body
15
- # @return [OpenAPIParser::Schemas::RequestBody, nil]
15
+ # @return [OpenAPIParser::Schemas::RequestBody, nil] return OpenAPI3 object
16
16
  openapi_attr_object :request_body, RequestBody, reference: true, schema_key: :requestBody
17
17
 
18
+ # @!attribute [r] responses
19
+ # @return [OpenAPIParser::Schemas::Responses, nil] return OpenAPI3 object
18
20
  openapi_attr_object :responses, Responses, reference: false
19
21
 
20
22
  def validate_request_body(content_type, params, options)
21
23
  request_body&.validate_request_body(content_type, params, options)
22
24
  end
23
25
 
26
+ # @param [Integer] status_code
24
27
  def validate_response_body(status_code, content_type, data)
25
28
  responses&.validate_response_body(status_code, content_type, data)
26
29
  end
@@ -36,18 +39,18 @@ module OpenAPIParser::Schemas
36
39
 
37
40
  private
38
41
 
39
- def path_parameter_hash
40
- @path_parameter_hash ||= (parameters || []).
41
- select(&:in_path?).
42
- map{ |param| [param.name, param] }.
43
- to_h
44
- end
45
-
46
- def query_parameter_hash
47
- @query_parameter_hash ||= (parameters || []).
48
- select(&:in_query?).
49
- map{ |param| [param.name, param] }.
50
- to_h
51
- end
42
+ def path_parameter_hash
43
+ @path_parameter_hash ||= (parameters || []).
44
+ select(&:in_path?).
45
+ map { |param| [param.name, param] }.
46
+ to_h
47
+ end
48
+
49
+ def query_parameter_hash
50
+ @query_parameter_hash ||= (parameters || []).
51
+ select(&:in_query?).
52
+ map { |param| [param.name, param] }.
53
+ to_h
54
+ end
52
55
  end
53
56
  end
@@ -12,11 +12,11 @@ module OpenAPIParser::Schemas
12
12
  openapi_attr_object :schema, Schema, reference: true
13
13
 
14
14
  def in_query?
15
- self.in == "query"
15
+ self.in == 'query'
16
16
  end
17
17
 
18
18
  def in_path?
19
- self.in == "path"
19
+ self.in == 'path'
20
20
  end
21
21
 
22
22
  # @return [Object] coerced or original params
@@ -2,16 +2,23 @@
2
2
 
3
3
  module OpenAPIParser::Schemas
4
4
  class RequestBody < Base
5
+ include OpenAPIParser::MediaTypeSelectable
6
+
7
+ # @!attribute [r] description
8
+ # @return [String] description data
9
+ # @!attribute [r] required
10
+ # @return [Boolean] required bool data
5
11
  openapi_attr_values :description, :required
6
12
 
7
13
  # @!attribute [r] content
8
- # @return [Hash{String => MediaType}, nil]
14
+ # @return [Hash{String => MediaType}, nil] content type to MediaType object
9
15
  openapi_attr_hash_object :content, MediaType, reference: false
10
16
 
11
- def validate_request_body(_content_type, params, options)
12
- # TODO: now support application/json only :(
13
-
14
- media_type = content['application/json']
17
+ # @param [String] content_type
18
+ # @param [Hash] params
19
+ # @param [OpenAPIParser::SchemaValidator::Options] options
20
+ def validate_request_body(content_type, params, options)
21
+ media_type = select_media_type(content_type, content)
15
22
  return params unless media_type
16
23
 
17
24
  media_type.validate_parameter(params, options)
@@ -3,16 +3,16 @@
3
3
 
4
4
  module OpenAPIParser::Schemas
5
5
  class Response < Base
6
+ include OpenAPIParser::MediaTypeSelectable
7
+
6
8
  openapi_attr_values :description
7
9
 
8
10
  # @!attribute [r] content
9
- # @return [Hash{String => MediaType}, nil]
11
+ # @return [Hash{String => MediaType}, nil] content_type to MediaType hash
10
12
  openapi_attr_hash_object :content, MediaType, reference: false
11
13
 
12
14
  def validate_parameter(content_type, params)
13
- # TODO: support wildcard type like application/* (OpenAPI3 definition)
14
-
15
- media_type = content[content_type]
15
+ media_type = select_media_type(content_type, content)
16
16
  return nil unless media_type
17
17
 
18
18
  options = ::OpenAPIParser::SchemaValidator::Options.new # response validator not support any options
@@ -3,22 +3,40 @@
3
3
  module OpenAPIParser::Schemas
4
4
  class Responses < Base
5
5
  # @!attribute [r] default
6
- # @return [Response, Reference, nil]
6
+ # @return [Response, Reference, nil] default response object
7
7
  openapi_attr_object :default, Response, reference: true
8
8
 
9
9
  # @!attribute [r] response
10
- # @return [Hash{String => Response, Reference}, nil]
10
+ # @return [Hash{String => Response, Reference}, nil] response object indexed by status code. see: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#patterned-fields-1
11
11
  openapi_attr_hash_body_objects 'response', Response, reject_keys: [:default], allow_reference: true, allow_data_type: false
12
12
 
13
+ # validate params data by definition
14
+ # find response object by status_code and content_type
15
+ # https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#patterned-fields-1
16
+ # @param [Integer] status_code
17
+ # @param [String] content_type
18
+ # @param [Hash] params
13
19
  def validate_response_body(status_code, content_type, params)
14
- # TODO: support wildcard status code like 2XX
15
20
  return nil unless response
16
21
 
17
22
  res = response[status_code.to_s]
18
23
  return res.validate_parameter(content_type, params) if res
19
24
 
25
+ wild_card = status_code_to_wild_card(status_code)
26
+ res = response[wild_card]
27
+ return res.validate_parameter(content_type, params) if res
20
28
 
21
29
  default&.validate_parameter(content_type, params)
22
30
  end
31
+
32
+ private
33
+
34
+ # parse 400 -> 4xx
35
+ # OpenAPI3 allow 1xx, 2xx, 3xx... only, don't allow 41x
36
+ # @param [Integer] status_code
37
+ def status_code_to_wild_card(status_code)
38
+ top = status_code / 100
39
+ "#{top}XX"
40
+ end
23
41
  end
24
42
  end