openapi_parser_firetail 1.0.0

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.
Files changed (93) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ci.yaml +25 -0
  3. data/.gitignore +15 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +13 -0
  6. data/.rubocop_ignore.yml +6 -0
  7. data/.ruby-version +1 -0
  8. data/CHANGELOG.md +132 -0
  9. data/CODE_OF_CONDUCT.md +74 -0
  10. data/Gemfile +6 -0
  11. data/LICENSE.txt +21 -0
  12. data/README.md +112 -0
  13. data/Rakefile +10 -0
  14. data/Steepfile +11 -0
  15. data/bin/console +14 -0
  16. data/bin/setup +8 -0
  17. data/lib/openapi_parser/concern.rb +5 -0
  18. data/lib/openapi_parser/concerns/expandable.rb +87 -0
  19. data/lib/openapi_parser/concerns/findable.rb +54 -0
  20. data/lib/openapi_parser/concerns/media_type_selectable.rb +29 -0
  21. data/lib/openapi_parser/concerns/parameter_validatable.rb +62 -0
  22. data/lib/openapi_parser/concerns/parser/core.rb +21 -0
  23. data/lib/openapi_parser/concerns/parser/hash.rb +10 -0
  24. data/lib/openapi_parser/concerns/parser/hash_body.rb +12 -0
  25. data/lib/openapi_parser/concerns/parser/list.rb +10 -0
  26. data/lib/openapi_parser/concerns/parser/object.rb +14 -0
  27. data/lib/openapi_parser/concerns/parser/value.rb +14 -0
  28. data/lib/openapi_parser/concerns/parser.rb +45 -0
  29. data/lib/openapi_parser/concerns/schema_loader/base.rb +28 -0
  30. data/lib/openapi_parser/concerns/schema_loader/creator.rb +48 -0
  31. data/lib/openapi_parser/concerns/schema_loader/hash_body_loader.rb +37 -0
  32. data/lib/openapi_parser/concerns/schema_loader/hash_objects_loader.rb +29 -0
  33. data/lib/openapi_parser/concerns/schema_loader/list_loader.rb +28 -0
  34. data/lib/openapi_parser/concerns/schema_loader/objects_loader.rb +21 -0
  35. data/lib/openapi_parser/concerns/schema_loader/values_loader.rb +10 -0
  36. data/lib/openapi_parser/concerns/schema_loader.rb +58 -0
  37. data/lib/openapi_parser/config.rb +55 -0
  38. data/lib/openapi_parser/errors.rb +281 -0
  39. data/lib/openapi_parser/parameter_validator.rb +33 -0
  40. data/lib/openapi_parser/path_item_finder.rb +161 -0
  41. data/lib/openapi_parser/reference_expander.rb +9 -0
  42. data/lib/openapi_parser/request_operation.rb +90 -0
  43. data/lib/openapi_parser/schema_validator/all_of_validator.rb +40 -0
  44. data/lib/openapi_parser/schema_validator/any_of_validator.rb +18 -0
  45. data/lib/openapi_parser/schema_validator/array_validator.rb +32 -0
  46. data/lib/openapi_parser/schema_validator/base.rb +39 -0
  47. data/lib/openapi_parser/schema_validator/boolean_validator.rb +29 -0
  48. data/lib/openapi_parser/schema_validator/enumable.rb +13 -0
  49. data/lib/openapi_parser/schema_validator/float_validator.rb +34 -0
  50. data/lib/openapi_parser/schema_validator/integer_validator.rb +32 -0
  51. data/lib/openapi_parser/schema_validator/minimum_maximum.rb +38 -0
  52. data/lib/openapi_parser/schema_validator/nil_validator.rb +11 -0
  53. data/lib/openapi_parser/schema_validator/object_validator.rb +56 -0
  54. data/lib/openapi_parser/schema_validator/one_of_validator.rb +22 -0
  55. data/lib/openapi_parser/schema_validator/options.rb +29 -0
  56. data/lib/openapi_parser/schema_validator/string_validator.rb +108 -0
  57. data/lib/openapi_parser/schema_validator/unspecified_type_validator.rb +8 -0
  58. data/lib/openapi_parser/schema_validator.rb +164 -0
  59. data/lib/openapi_parser/schemas/base.rb +28 -0
  60. data/lib/openapi_parser/schemas/classes.rb +22 -0
  61. data/lib/openapi_parser/schemas/components.rb +32 -0
  62. data/lib/openapi_parser/schemas/discriminator.rb +11 -0
  63. data/lib/openapi_parser/schemas/header.rb +18 -0
  64. data/lib/openapi_parser/schemas/info.rb +6 -0
  65. data/lib/openapi_parser/schemas/media_type.rb +18 -0
  66. data/lib/openapi_parser/schemas/openapi.rb +63 -0
  67. data/lib/openapi_parser/schemas/operation.rb +50 -0
  68. data/lib/openapi_parser/schemas/parameter.rb +20 -0
  69. data/lib/openapi_parser/schemas/path_item.rb +22 -0
  70. data/lib/openapi_parser/schemas/paths.rb +7 -0
  71. data/lib/openapi_parser/schemas/reference.rb +7 -0
  72. data/lib/openapi_parser/schemas/request_body.rb +34 -0
  73. data/lib/openapi_parser/schemas/response.rb +54 -0
  74. data/lib/openapi_parser/schemas/responses.rb +56 -0
  75. data/lib/openapi_parser/schemas/schema.rb +117 -0
  76. data/lib/openapi_parser/schemas/security.rb +7 -0
  77. data/lib/openapi_parser/schemas/security_schemes.rb +20 -0
  78. data/lib/openapi_parser/schemas.rb +20 -0
  79. data/lib/openapi_parser/version.rb +3 -0
  80. data/lib/openapi_parser.rb +108 -0
  81. data/openapi_parser.gemspec +43 -0
  82. data/sig/openapi_parser/config.rbs +19 -0
  83. data/sig/openapi_parser/errors.rbs +22 -0
  84. data/sig/openapi_parser/reference_expander.rbs +3 -0
  85. data/sig/openapi_parser/schema_validator.rbs +46 -0
  86. data/sig/openapi_parser/schema_validators/base.rbs +18 -0
  87. data/sig/openapi_parser/schema_validators/options.rbs +17 -0
  88. data/sig/openapi_parser/schemas/base.rbs +17 -0
  89. data/sig/openapi_parser/version.rbs +3 -0
  90. data/sig/openapi_parser.rbs +19 -0
  91. data/sig/types.rbs +13 -0
  92. data/sig/wip_types.rbs +64 -0
  93. metadata +288 -0
@@ -0,0 +1,11 @@
1
+ module OpenAPIParser::Schemas
2
+ class Discriminator < Base
3
+ # @!attribute [r] property_name
4
+ # @return [String, nil]
5
+ openapi_attr_value :property_name, schema_key: :propertyName
6
+
7
+ # @!attribute [r] mapping
8
+ # @return [Hash{String => String]
9
+ openapi_attr_value :mapping
10
+ end
11
+ end
@@ -0,0 +1,18 @@
1
+ module OpenAPIParser::Schemas
2
+ class Header < Base
3
+ openapi_attr_values :description, :required, :deprecated, :style, :explode, :example
4
+
5
+ openapi_attr_value :allow_empty_value, schema_key: :allowEmptyValue
6
+ openapi_attr_value :allow_reserved, schema_key: :allowReserved
7
+
8
+ # @!attribute [r] schema
9
+ # @return [Schema, Reference, nil]
10
+ openapi_attr_object :schema, Schema, reference: true
11
+
12
+ # validate by schema
13
+ # @param [Object] value
14
+ def validate(value)
15
+ OpenAPIParser::SchemaValidator.validate(value, schema, OpenAPIParser::SchemaValidator::Options.new)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,6 @@
1
+ module OpenAPIParser::Schemas
2
+ class Info < Base
3
+
4
+ openapi_attr_values :title, :version
5
+ end
6
+ end
@@ -0,0 +1,18 @@
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] OpenAPI3 Schema object
9
+ openapi_attr_object :schema, Schema, reference: true
10
+
11
+ # validate params by schema definitions
12
+ # @param [Hash] params
13
+ # @param [OpenAPIParser::SchemaValidator::Options] options
14
+ def validate_parameter(params, options)
15
+ OpenAPIParser::SchemaValidator.validate(params, schema, options)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,63 @@
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, config, uri: nil, schema_registry: {})
9
+ super('#', nil, self, raw_schema)
10
+ @find_object_cache = {}
11
+ @path_item_finder = OpenAPIParser::PathItemFinder.new(paths) if paths # invalid definition
12
+ @config = config
13
+ @uri = uri
14
+ @schema_registry = schema_registry
15
+
16
+ # schema_registery is shared among schemas, and prevents a schema from being loaded multiple times
17
+ schema_registry[uri] = self if uri
18
+ end
19
+
20
+ # @!attribute [r] openapi
21
+ # @return [String, nil]
22
+ openapi_attr_values :openapi
23
+
24
+ # @!attribute [r] paths
25
+ # @return [Paths, nil]
26
+ openapi_attr_object :paths, Paths, reference: false
27
+
28
+ # @!attribute [r] components
29
+ # @return [Components, nil]
30
+ openapi_attr_object :components, Components, reference: false
31
+
32
+ # @!attribute [r] info
33
+ # @return [Info, nil]
34
+ openapi_attr_object :info, Info, reference: false
35
+
36
+ # @return [OpenAPIParser::RequestOperation, nil]
37
+ def request_operation(http_method, request_path)
38
+ OpenAPIParser::RequestOperation.create(http_method, request_path, @path_item_finder, @config, components&.security_schemes)
39
+ end
40
+
41
+ # load another schema with shared config and schema_registry
42
+ # @return [OpenAPIParser::Schemas::OpenAPI]
43
+ def load_another_schema(uri)
44
+ resolved_uri = resolve_uri(uri)
45
+ return if resolved_uri.nil?
46
+
47
+ loaded = @schema_registry[resolved_uri]
48
+ return loaded if loaded
49
+
50
+ OpenAPIParser.load_uri(resolved_uri, config: @config, schema_registry: @schema_registry)
51
+ end
52
+
53
+ private
54
+
55
+ def resolve_uri(uri)
56
+ if uri.absolute?
57
+ uri
58
+ else
59
+ @uri&.merge(uri)
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,50 @@
1
+ # TODO: externalDocs
2
+ # TODO: callbacks
3
+ # TODO: security
4
+ # TODO: servers
5
+
6
+ module OpenAPIParser::Schemas
7
+ class Operation < Base
8
+ include OpenAPIParser::ParameterValidatable
9
+
10
+ openapi_attr_values :tags, :summary, :description, :deprecated, :security
11
+
12
+ openapi_attr_value :operation_id, schema_key: :operationId
13
+
14
+ openapi_attr_list_object :parameters, Parameter, reference: true
15
+
16
+ # @!attribute [r] request_body
17
+ # @return [OpenAPIParser::Schemas::RequestBody, nil] return OpenAPI3 object
18
+ openapi_attr_object :request_body, RequestBody, reference: true, schema_key: :requestBody
19
+
20
+ # @!attribute [r] responses
21
+ # @return [OpenAPIParser::Schemas::Responses, nil] return OpenAPI3 object
22
+ openapi_attr_object :responses, Responses, reference: false
23
+
24
+ def validate_request_body(content_type, params, options)
25
+ request_body&.validate_request_body(content_type, params, options)
26
+ end
27
+
28
+ # @param [OpenAPIParser::RequestOperation::ValidatableResponseBody] response_body
29
+ # @param [OpenAPIParser::SchemaValidator::ResponseValidateOptions] response_validate_options
30
+ def validate_response(response_body, response_validate_options)
31
+ responses&.validate(response_body, response_validate_options)
32
+ end
33
+
34
+ def validate_security_schemes(securitySchemes, headers)
35
+ securitySchemes&.each do |securityScheme|
36
+ # check if the endpoint has security in schema
37
+ if security
38
+ # if security exists, check what securitySchemas used for enforcing
39
+ security.each do |s|
40
+ # securityScheme[0] is the securitySchema name
41
+ if s == securityScheme[0]
42
+ # securitySchema[1] is the values like "type", "scheme" and bearerFormat
43
+ securityScheme[1].validate_security_schemes(securityScheme[1], headers)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,20 @@
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
+ # @!attribute [r] schema
11
+ # @return [Schema, Reference, nil]
12
+ openapi_attr_object :schema, Schema, reference: true
13
+
14
+ # @return [Object] coerced or original params
15
+ # @param [OpenAPIParser::SchemaValidator::Options] options
16
+ def validate_params(params, options)
17
+ ::OpenAPIParser::SchemaValidator.validate(params, schema, options)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,22 @@
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
+ public_send(method)
14
+ rescue NoMethodError
15
+ nil
16
+ end
17
+
18
+ def set_path_item_to_operation
19
+ [:get, :put, :post, :delete, :options, :head, :patch, :trace].each{ |method| operation(method)&.set_parent_path_item(self)}
20
+ end
21
+ end
22
+ 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, reference: true, allow_data_type: false
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module OpenAPIParser::Schemas
2
+ class Reference < Base
3
+ # @!attribute [r] ref
4
+ # @return [Base]
5
+ openapi_attr_value :ref, schema_key: '$ref'
6
+ end
7
+ end
@@ -0,0 +1,34 @@
1
+ # TODO: support extended property
2
+
3
+ module OpenAPIParser::Schemas
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
11
+ openapi_attr_values :description, :required
12
+
13
+ # @!attribute [r] content
14
+ # @return [Hash{String => MediaType}, nil] content type to MediaType object
15
+ openapi_attr_hash_object :content, MediaType, reference: false
16
+
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)
22
+ return params unless media_type
23
+
24
+ media_type.validate_parameter(params, options)
25
+ end
26
+
27
+ # select media type by content_type (consider wild card definition)
28
+ # @param [String] content_type
29
+ # @return [OpenAPIParser::Schemas::MediaType, nil]
30
+ def select_media_type(content_type)
31
+ select_media_type_from_content(content_type, content)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,54 @@
1
+ # TODO: links
2
+
3
+ module OpenAPIParser::Schemas
4
+ class Response < Base
5
+ include OpenAPIParser::MediaTypeSelectable
6
+
7
+ openapi_attr_values :description
8
+
9
+ # @!attribute [r] content
10
+ # @return [Hash{String => MediaType}, nil] content_type to MediaType hash
11
+ openapi_attr_hash_object :content, MediaType, reference: false
12
+
13
+ # @!attribute [r] headers
14
+ # @return [Hash{String => Header}, nil] header string to Header
15
+ openapi_attr_hash_object :headers, Header, reference: true
16
+
17
+ # @param [OpenAPIParser::RequestOperation::ValidatableResponseBody] response_body
18
+ # @param [OpenAPIParser::SchemaValidator::ResponseValidateOptions] response_validate_options
19
+ def validate(response_body, response_validate_options)
20
+ validate_header(response_body.headers) if response_validate_options.validate_header
21
+
22
+ media_type = select_media_type(response_body.content_type)
23
+ unless media_type
24
+ raise ::OpenAPIParser::NotExistContentTypeDefinition, object_reference if response_validate_options.strict
25
+
26
+ return nil
27
+ end
28
+
29
+ options = ::OpenAPIParser::SchemaValidator::Options.new # response validator not support any options
30
+ media_type.validate_parameter(response_body.response_data, options)
31
+ end
32
+
33
+ # select media type by content_type (consider wild card definition)
34
+ # @param [String] content_type
35
+ # @return [OpenAPIParser::Schemas::MediaType, nil]
36
+ def select_media_type(content_type)
37
+ select_media_type_from_content(content_type, content)
38
+ end
39
+
40
+ private
41
+
42
+ # @param [Hash] response_headers
43
+ def validate_header(response_headers)
44
+ return unless headers
45
+
46
+ headers.each do |name, schema|
47
+ next unless response_headers.key?(name)
48
+
49
+ value = response_headers[name]
50
+ schema.validate(value)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,56 @@
1
+ # TODO: support extended property
2
+
3
+ module OpenAPIParser::Schemas
4
+ class Responses < Base
5
+ # @!attribute [r] default
6
+ # @return [Response, Reference, nil] default response object
7
+ openapi_attr_object :default, Response, reference: true
8
+
9
+ # @!attribute [r] response
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
+ openapi_attr_hash_body_objects 'response', Response, reject_keys: [:default], reference: true, allow_data_type: false
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 [OpenAPIParser::RequestOperation::ValidatableResponseBody] response_body
17
+ # @param [OpenAPIParser::SchemaValidator::ResponseValidateOptions] response_validate_options
18
+ def validate(response_body, response_validate_options)
19
+ return nil unless response
20
+
21
+ if (res = find_response_object(response_body.status_code))
22
+
23
+ return res.validate(response_body, response_validate_options)
24
+ end
25
+
26
+ raise ::OpenAPIParser::NotExistStatusCodeDefinition, object_reference if response_validate_options.strict
27
+
28
+ nil
29
+ end
30
+
31
+ private
32
+
33
+ # @param [Integer] status_code
34
+ # @return [Response]
35
+ def find_response_object(status_code)
36
+ if (res = response[status_code.to_s])
37
+ return res
38
+ end
39
+
40
+ wild_card = status_code_to_wild_card(status_code)
41
+ if (res = response[wild_card])
42
+ return res
43
+ end
44
+
45
+ default
46
+ end
47
+
48
+ # parse 400 -> 4xx
49
+ # OpenAPI3 allow 1xx, 2xx, 3xx... only, don't allow 41x
50
+ # @param [Integer] status_code
51
+ def status_code_to_wild_card(status_code)
52
+ top = status_code / 100
53
+ "#{top}XX"
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,117 @@
1
+ # TODO: support 'not' because I need check reference...
2
+ # TODO: support '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] discriminator
105
+ # @return [Discriminator, nil]
106
+ openapi_attr_object :discriminator, Discriminator
107
+
108
+ # @!attribute [r] additional_properties
109
+ # @return [Boolean, Schema, Reference, nil]
110
+ openapi_attr_object :additional_properties, Schema, reference: true, allow_data_type: true, schema_key: :additionalProperties
111
+ # additional_properties have default value
112
+ # we should add default value feature in openapi_attr_object method, but we need temporary fix so override attr_reader
113
+ def additional_properties
114
+ @additional_properties.nil? ? true : @additional_properties
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,7 @@
1
+ module OpenAPIParser::Schemas
2
+ class Security < Base
3
+
4
+ def validate_security_requirements(securityScheme, headers)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,20 @@
1
+ require 'jwt'
2
+ module OpenAPIParser::Schemas
3
+ class SecuritySchemes < Base
4
+
5
+ openapi_attr_values :type, :description, :scheme
6
+ openapi_attr_value :bearer_format, schema_key: :bearerFormat
7
+
8
+ def validate_security_schemes(securityScheme, headers)
9
+ if self.type == "http" && self.scheme == "bearer" && self.bearer_format == "JWT"
10
+ raise "need authorization" unless headers["AUTHORIZATION"]
11
+ raise "not bearer" unless headers["AUTHORIZATION"].split[0] == "Bearer"
12
+
13
+ # check if the JWT token is being sent and try to decode.
14
+ # if JWT token does not exist or token cannot decode, then deny access
15
+ token = headers["AUTHORIZATION"].split[1]
16
+ JWT.decode token, nil, false
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ require_relative 'schemas/classes'
2
+
3
+ require_relative 'schemas/base'
4
+ require_relative 'schemas/discriminator'
5
+ require_relative 'schemas/openapi'
6
+ require_relative 'schemas/paths'
7
+ require_relative 'schemas/path_item'
8
+ require_relative 'schemas/operation'
9
+ require_relative 'schemas/parameter'
10
+ require_relative 'schemas/reference'
11
+ require_relative 'schemas/request_body'
12
+ require_relative 'schemas/response'
13
+ require_relative 'schemas/responses'
14
+ require_relative 'schemas/components'
15
+ require_relative 'schemas/media_type'
16
+ require_relative 'schemas/schema'
17
+ require_relative 'schemas/header'
18
+ require_relative 'schemas/security_schemes'
19
+ require_relative 'schemas/info'
20
+ require_relative 'schemas/security'
@@ -0,0 +1,3 @@
1
+ module OpenAPIParser
2
+ VERSION = '1.0.0'.freeze
3
+ end
@@ -0,0 +1,108 @@
1
+ require 'uri'
2
+ require 'time'
3
+ require 'json'
4
+ require 'psych'
5
+ require 'pathname'
6
+ require 'open-uri'
7
+
8
+ require 'openapi_parser/version'
9
+ require 'openapi_parser/config'
10
+ require 'openapi_parser/errors'
11
+ require 'openapi_parser/concern'
12
+ require 'openapi_parser/schemas'
13
+ require 'openapi_parser/path_item_finder'
14
+ require 'openapi_parser/request_operation'
15
+ require 'openapi_parser/schema_validator'
16
+ require 'openapi_parser/parameter_validator'
17
+ require 'openapi_parser/reference_expander'
18
+
19
+ module OpenAPIParser
20
+ class << self
21
+ # Load schema hash object. Uri is not set for returned schema.
22
+ # @return [OpenAPIParser::Schemas::OpenAPI]
23
+ def parse(schema, config = {})
24
+ load_hash(schema, config: Config.new(config), uri: nil, schema_registry: {})
25
+ end
26
+
27
+ # @param filepath [String] Path of the file containing the passed schema.
28
+ # Used for resolving remote $ref if provided.
29
+ # If file path is relative, it is resolved using working directory.
30
+ # @return [OpenAPIParser::Schemas::OpenAPI]
31
+ def parse_with_filepath(schema, filepath, config = {})
32
+ load_hash(schema, config: Config.new(config), uri: filepath && file_uri(filepath), schema_registry: {})
33
+ end
34
+
35
+ # Load schema in specified filepath. If file path is relative, it is resolved using working directory.
36
+ # @return [OpenAPIParser::Schemas::OpenAPI]
37
+ def load(filepath, config = {})
38
+ load_uri(file_uri(filepath), config: Config.new(config), schema_registry: {})
39
+ end
40
+
41
+ # Load schema located by the passed uri. Uri must be absolute.
42
+ # @return [OpenAPIParser::Schemas::OpenAPI]
43
+ def load_uri(uri, config:, schema_registry:)
44
+ # Open-uri doesn't open file scheme uri, so we try to open file path directly
45
+ # File scheme uri which points to a remote file is not supported.
46
+ uri_path = uri.path
47
+ raise "file not found" if uri_path.nil?
48
+
49
+ content = if uri.scheme == 'file'
50
+ open(uri_path)&.read
51
+ elsif uri.is_a?(OpenURI::OpenRead)
52
+ uri.open()&.read
53
+ end
54
+
55
+ extension = Pathname.new(uri_path).extname
56
+ load_hash(parse_file(content, extension), config: config, uri: uri, schema_registry: schema_registry)
57
+ end
58
+
59
+ private
60
+
61
+ def file_uri(filepath)
62
+ path = Pathname.new(filepath)
63
+ path = Pathname.getwd + path if path.relative?
64
+ URI.join("file:///", path.to_s)
65
+ end
66
+
67
+ def parse_file(content, ext)
68
+ case ext.downcase
69
+ when '.yaml', '.yml'
70
+ parse_yaml(content)
71
+ when '.json'
72
+ parse_json(content)
73
+ else
74
+ # When extension is something we don't know, try to parse as json first. If it fails, parse as yaml
75
+ begin
76
+ parse_json(content)
77
+ rescue JSON::ParserError
78
+ parse_yaml(content)
79
+ end
80
+ end
81
+ end
82
+
83
+ def parse_yaml(content)
84
+ # FIXME: when drop ruby 2.5, we should use permitted_classes
85
+ (Gem::Version.create(RUBY_VERSION) < Gem::Version.create("2.6.0")) ?
86
+ Psych.safe_load(content, [Date, Time]) :
87
+ Psych.safe_load(content, permitted_classes: [Date, Time])
88
+ end
89
+
90
+ def parse_json(content)
91
+ raise "json content is nil" unless content
92
+ JSON.parse(content)
93
+ end
94
+
95
+ def load_hash(hash, config:, uri:, schema_registry:)
96
+ root = Schemas::OpenAPI.new(hash, config, uri: uri, schema_registry: schema_registry)
97
+
98
+ OpenAPIParser::ReferenceExpander.expand(root, config.strict_reference_validation) if config.expand_reference
99
+
100
+ # TODO: use callbacks
101
+ root.paths&.path&.values&.each do | path_item |
102
+ path_item.set_path_item_to_operation
103
+ end
104
+
105
+ root
106
+ end
107
+ end
108
+ end