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.
- checksums.yaml +7 -0
- data/.github/workflows/ci.yaml +25 -0
- data/.gitignore +15 -0
- data/.rspec +3 -0
- data/.rubocop.yml +13 -0
- data/.rubocop_ignore.yml +6 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +132 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +112 -0
- data/Rakefile +10 -0
- data/Steepfile +11 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/openapi_parser/concern.rb +5 -0
- data/lib/openapi_parser/concerns/expandable.rb +87 -0
- data/lib/openapi_parser/concerns/findable.rb +54 -0
- data/lib/openapi_parser/concerns/media_type_selectable.rb +29 -0
- data/lib/openapi_parser/concerns/parameter_validatable.rb +62 -0
- data/lib/openapi_parser/concerns/parser/core.rb +21 -0
- data/lib/openapi_parser/concerns/parser/hash.rb +10 -0
- data/lib/openapi_parser/concerns/parser/hash_body.rb +12 -0
- data/lib/openapi_parser/concerns/parser/list.rb +10 -0
- data/lib/openapi_parser/concerns/parser/object.rb +14 -0
- data/lib/openapi_parser/concerns/parser/value.rb +14 -0
- data/lib/openapi_parser/concerns/parser.rb +45 -0
- data/lib/openapi_parser/concerns/schema_loader/base.rb +28 -0
- data/lib/openapi_parser/concerns/schema_loader/creator.rb +48 -0
- data/lib/openapi_parser/concerns/schema_loader/hash_body_loader.rb +37 -0
- data/lib/openapi_parser/concerns/schema_loader/hash_objects_loader.rb +29 -0
- data/lib/openapi_parser/concerns/schema_loader/list_loader.rb +28 -0
- data/lib/openapi_parser/concerns/schema_loader/objects_loader.rb +21 -0
- data/lib/openapi_parser/concerns/schema_loader/values_loader.rb +10 -0
- data/lib/openapi_parser/concerns/schema_loader.rb +58 -0
- data/lib/openapi_parser/config.rb +55 -0
- data/lib/openapi_parser/errors.rb +281 -0
- data/lib/openapi_parser/parameter_validator.rb +33 -0
- data/lib/openapi_parser/path_item_finder.rb +161 -0
- data/lib/openapi_parser/reference_expander.rb +9 -0
- data/lib/openapi_parser/request_operation.rb +90 -0
- data/lib/openapi_parser/schema_validator/all_of_validator.rb +40 -0
- data/lib/openapi_parser/schema_validator/any_of_validator.rb +18 -0
- data/lib/openapi_parser/schema_validator/array_validator.rb +32 -0
- data/lib/openapi_parser/schema_validator/base.rb +39 -0
- data/lib/openapi_parser/schema_validator/boolean_validator.rb +29 -0
- data/lib/openapi_parser/schema_validator/enumable.rb +13 -0
- data/lib/openapi_parser/schema_validator/float_validator.rb +34 -0
- data/lib/openapi_parser/schema_validator/integer_validator.rb +32 -0
- data/lib/openapi_parser/schema_validator/minimum_maximum.rb +38 -0
- data/lib/openapi_parser/schema_validator/nil_validator.rb +11 -0
- data/lib/openapi_parser/schema_validator/object_validator.rb +56 -0
- data/lib/openapi_parser/schema_validator/one_of_validator.rb +22 -0
- data/lib/openapi_parser/schema_validator/options.rb +29 -0
- data/lib/openapi_parser/schema_validator/string_validator.rb +108 -0
- data/lib/openapi_parser/schema_validator/unspecified_type_validator.rb +8 -0
- data/lib/openapi_parser/schema_validator.rb +164 -0
- data/lib/openapi_parser/schemas/base.rb +28 -0
- data/lib/openapi_parser/schemas/classes.rb +22 -0
- data/lib/openapi_parser/schemas/components.rb +32 -0
- data/lib/openapi_parser/schemas/discriminator.rb +11 -0
- data/lib/openapi_parser/schemas/header.rb +18 -0
- data/lib/openapi_parser/schemas/info.rb +6 -0
- data/lib/openapi_parser/schemas/media_type.rb +18 -0
- data/lib/openapi_parser/schemas/openapi.rb +63 -0
- data/lib/openapi_parser/schemas/operation.rb +50 -0
- data/lib/openapi_parser/schemas/parameter.rb +20 -0
- data/lib/openapi_parser/schemas/path_item.rb +22 -0
- data/lib/openapi_parser/schemas/paths.rb +7 -0
- data/lib/openapi_parser/schemas/reference.rb +7 -0
- data/lib/openapi_parser/schemas/request_body.rb +34 -0
- data/lib/openapi_parser/schemas/response.rb +54 -0
- data/lib/openapi_parser/schemas/responses.rb +56 -0
- data/lib/openapi_parser/schemas/schema.rb +117 -0
- data/lib/openapi_parser/schemas/security.rb +7 -0
- data/lib/openapi_parser/schemas/security_schemes.rb +20 -0
- data/lib/openapi_parser/schemas.rb +20 -0
- data/lib/openapi_parser/version.rb +3 -0
- data/lib/openapi_parser.rb +108 -0
- data/openapi_parser.gemspec +43 -0
- data/sig/openapi_parser/config.rbs +19 -0
- data/sig/openapi_parser/errors.rbs +22 -0
- data/sig/openapi_parser/reference_expander.rbs +3 -0
- data/sig/openapi_parser/schema_validator.rbs +46 -0
- data/sig/openapi_parser/schema_validators/base.rbs +18 -0
- data/sig/openapi_parser/schema_validators/options.rbs +17 -0
- data/sig/openapi_parser/schemas/base.rbs +17 -0
- data/sig/openapi_parser/version.rbs +3 -0
- data/sig/openapi_parser.rbs +19 -0
- data/sig/types.rbs +13 -0
- data/sig/wip_types.rbs +64 -0
- 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,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,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,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,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
|