gitlab-grape-openapi 0.0.0 → 0.1.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 +4 -4
- data/LICENSE +1 -1
- data/README.md +222 -4
- data/lib/gitlab/grape_openapi/concerns/fail_fast_annotatable.rb +23 -0
- data/lib/gitlab/grape_openapi/concerns/limit_resolver.rb +31 -0
- data/lib/gitlab/grape_openapi/concerns/regex_converter.rb +58 -0
- data/lib/gitlab/grape_openapi/concerns/serializable.rb +19 -0
- data/lib/gitlab/grape_openapi/configuration.rb +24 -0
- data/lib/gitlab/grape_openapi/converters/coercer_resolver.rb +74 -0
- data/lib/gitlab/grape_openapi/converters/entity_converter.rb +267 -0
- data/lib/gitlab/grape_openapi/converters/operation_converter.rb +250 -0
- data/lib/gitlab/grape_openapi/converters/parameter_converter.rb +252 -0
- data/lib/gitlab/grape_openapi/converters/path_converter.rb +152 -0
- data/lib/gitlab/grape_openapi/converters/request_body_converter.rb +97 -0
- data/lib/gitlab/grape_openapi/converters/response_converter.rb +185 -0
- data/lib/gitlab/grape_openapi/converters/tag_converter.rb +36 -0
- data/lib/gitlab/grape_openapi/converters/type_resolver.rb +75 -0
- data/lib/gitlab/grape_openapi/generator.rb +60 -0
- data/lib/gitlab/grape_openapi/models/info.rb +29 -0
- data/lib/gitlab/grape_openapi/models/operation.rb +47 -0
- data/lib/gitlab/grape_openapi/models/parameter.rb +43 -0
- data/lib/gitlab/grape_openapi/models/path_item.rb +26 -0
- data/lib/gitlab/grape_openapi/models/request_body/parameter_schema.rb +250 -0
- data/lib/gitlab/grape_openapi/models/request_body/parameters.rb +87 -0
- data/lib/gitlab/grape_openapi/models/response.rb +48 -0
- data/lib/gitlab/grape_openapi/models/schema.rb +61 -0
- data/lib/gitlab/grape_openapi/models/security_scheme.rb +130 -0
- data/lib/gitlab/grape_openapi/models/server.rb +31 -0
- data/lib/gitlab/grape_openapi/models/server_variable.rb +25 -0
- data/lib/gitlab/grape_openapi/models/tag.rb +44 -0
- data/lib/gitlab/grape_openapi/request_body_registry.rb +57 -0
- data/lib/gitlab/grape_openapi/schema_registry.rb +26 -0
- data/lib/gitlab/grape_openapi/serializers/time.rb +19 -0
- data/lib/gitlab/grape_openapi/tag_registry.rb +29 -0
- data/lib/gitlab/grape_openapi/version.rb +8 -0
- data/lib/gitlab-grape-openapi.rb +64 -0
- metadata +162 -12
- data/lib/gitlab/grape/openapi/version.rb +0 -9
- data/lib/gitlab/grape/openapi.rb +0 -21
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module GrapeOpenapi
|
|
5
|
+
module Models
|
|
6
|
+
# https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#response-object
|
|
7
|
+
class Response
|
|
8
|
+
attr_reader :status_code, :description, :entity_class, :headers, :content_type
|
|
9
|
+
|
|
10
|
+
def initialize(
|
|
11
|
+
status_code:, description:, entity_class:, headers: {}, content_type: 'application/json',
|
|
12
|
+
example: nil, examples: nil)
|
|
13
|
+
@status_code = status_code.to_s
|
|
14
|
+
@description = description
|
|
15
|
+
@entity_class = entity_class
|
|
16
|
+
@headers = headers
|
|
17
|
+
@content_type = content_type
|
|
18
|
+
@example = example
|
|
19
|
+
@examples = examples
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def to_h(schema_registry)
|
|
23
|
+
response = {
|
|
24
|
+
description: description,
|
|
25
|
+
content: {
|
|
26
|
+
content_type => {
|
|
27
|
+
schema: { '$ref' => schema_ref(schema_registry) },
|
|
28
|
+
example: @example,
|
|
29
|
+
examples: @examples
|
|
30
|
+
}.compact
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
response[:headers] = headers if headers.any?
|
|
35
|
+
|
|
36
|
+
response
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def schema_ref(schema_registry)
|
|
42
|
+
normalized_name = schema_registry.register(entity_class, nil)
|
|
43
|
+
"#/components/schemas/#{normalized_name}"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module GrapeOpenapi
|
|
5
|
+
module Models
|
|
6
|
+
# https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#schema-object
|
|
7
|
+
class Schema
|
|
8
|
+
attr_accessor :properties, :type
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
@properties = {}
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def method_missing(method_name, *_args)
|
|
15
|
+
raise NoMethodError unless respond_to_missing?(method_name)
|
|
16
|
+
|
|
17
|
+
properties[method_name]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def respond_to_missing?(method_name, _include_private = false)
|
|
21
|
+
properties.key?(method_name)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def to_h
|
|
25
|
+
build_schema_hash
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def build_schema_hash
|
|
31
|
+
{}.tap do |hash|
|
|
32
|
+
add_type(hash)
|
|
33
|
+
add_properties(hash)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def add_type(hash)
|
|
38
|
+
hash[:type] = type if type
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def add_properties(hash)
|
|
42
|
+
return if properties.empty?
|
|
43
|
+
|
|
44
|
+
hash[:properties] = properties.transform_values(&:to_h)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def description
|
|
48
|
+
@properties[:description]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def default
|
|
52
|
+
@properties[:default]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def example
|
|
56
|
+
@properties[:example]
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module GrapeOpenapi
|
|
5
|
+
module Models
|
|
6
|
+
# https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#security-scheme-object
|
|
7
|
+
class SecurityScheme
|
|
8
|
+
VALID_TYPES = %w[apiKey http oauth2 openIdConnect].freeze
|
|
9
|
+
VALID_IN_VALUES = %w[query header cookie].freeze
|
|
10
|
+
VALID_HTTP_SCHEMES = %w[basic bearer oauth].freeze
|
|
11
|
+
|
|
12
|
+
attr_accessor :type, :description, :name, :in, :scheme, :bearer_format,
|
|
13
|
+
:flows, :open_id_connect_url
|
|
14
|
+
|
|
15
|
+
def initialize(type:, **options)
|
|
16
|
+
@type = type
|
|
17
|
+
validate_type!
|
|
18
|
+
|
|
19
|
+
@description = options[:description]
|
|
20
|
+
|
|
21
|
+
case @type
|
|
22
|
+
when 'apiKey'
|
|
23
|
+
@name = options[:name] || raise(ArgumentError, "name is required for apiKey type")
|
|
24
|
+
@in = options[:in] || raise(ArgumentError, "in is required for apiKey type")
|
|
25
|
+
validate_in!
|
|
26
|
+
when 'http'
|
|
27
|
+
@scheme = options[:scheme] || raise(ArgumentError, "scheme is required for http type")
|
|
28
|
+
validate_http_scheme!
|
|
29
|
+
@bearer_format = options[:bearer_format] if @scheme == 'bearer'
|
|
30
|
+
when 'oauth2'
|
|
31
|
+
@flows = options[:flows] || raise(ArgumentError, "flows is required for oauth2 type")
|
|
32
|
+
validate_oauth2_flows!
|
|
33
|
+
when 'openIdConnect'
|
|
34
|
+
@open_id_connect_url = options[:open_id_connect_url] ||
|
|
35
|
+
raise(ArgumentError, "open_id_connect_url is required for openIdConnect type")
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def to_h
|
|
40
|
+
hash = { 'type' => @type }
|
|
41
|
+
hash['description'] = @description if @description
|
|
42
|
+
|
|
43
|
+
case @type
|
|
44
|
+
when 'apiKey'
|
|
45
|
+
hash['name'] = @name
|
|
46
|
+
hash['in'] = @in
|
|
47
|
+
when 'http'
|
|
48
|
+
hash['scheme'] = @scheme
|
|
49
|
+
hash['bearerFormat'] = @bearer_format if @bearer_format
|
|
50
|
+
when 'oauth2'
|
|
51
|
+
hash['flows'] = flows_to_hash(@flows)
|
|
52
|
+
when 'openIdConnect'
|
|
53
|
+
hash['openIdConnectUrl'] = @open_id_connect_url
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
hash
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def validate_type!
|
|
62
|
+
return if VALID_TYPES.include?(@type)
|
|
63
|
+
|
|
64
|
+
raise ArgumentError, "Invalid type: #{@type}. Must be one of: #{VALID_TYPES.join(', ')}"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def validate_in!
|
|
68
|
+
return if VALID_IN_VALUES.include?(@in)
|
|
69
|
+
|
|
70
|
+
raise ArgumentError, "Invalid 'in' value: #{@in}. Must be one of: #{VALID_IN_VALUES.join(', ')}"
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def validate_http_scheme!
|
|
74
|
+
return if VALID_HTTP_SCHEMES.include?(@scheme.downcase)
|
|
75
|
+
|
|
76
|
+
raise ArgumentError, "Invalid HTTP scheme: #{@scheme}. Common values: #{VALID_HTTP_SCHEMES.join(', ')}"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def validate_oauth2_flows!
|
|
80
|
+
raise ArgumentError, "flows must be a Hash" unless @flows.is_a?(Hash)
|
|
81
|
+
|
|
82
|
+
valid_flow_types = %w[implicit password clientCredentials authorizationCode]
|
|
83
|
+
@flows.each do |flow_type, flow_config|
|
|
84
|
+
unless valid_flow_types.include?(flow_type.to_s)
|
|
85
|
+
raise ArgumentError, "Invalid flow type: #{flow_type}. Must be one of: #{valid_flow_types.join(', ')}"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
validate_flow_config!(flow_type.to_s, flow_config)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# rubocop:disable Metrics/CyclomaticComplexity -- Method is clear and readable
|
|
93
|
+
def validate_flow_config!(flow_type, config)
|
|
94
|
+
raise ArgumentError, "Flow configuration must be a Hash" unless config.is_a?(Hash)
|
|
95
|
+
|
|
96
|
+
case flow_type
|
|
97
|
+
when 'implicit'
|
|
98
|
+
raise ArgumentError, "authorizationUrl required for implicit flow" unless config[:authorizationUrl]
|
|
99
|
+
raise ArgumentError, "scopes required for implicit flow" unless config[:scopes]
|
|
100
|
+
when 'password'
|
|
101
|
+
raise ArgumentError, "tokenUrl required for password flow" unless config[:tokenUrl]
|
|
102
|
+
raise ArgumentError, "scopes required for password flow" unless config[:scopes]
|
|
103
|
+
when 'clientCredentials'
|
|
104
|
+
raise ArgumentError, "tokenUrl required for clientCredentials flow" unless config[:tokenUrl]
|
|
105
|
+
raise ArgumentError, "scopes required for clientCredentials flow" unless config[:scopes]
|
|
106
|
+
when 'authorizationCode'
|
|
107
|
+
raise ArgumentError, "authorizationUrl required for authorizationCode flow" unless config[:authorizationUrl]
|
|
108
|
+
raise ArgumentError, "tokenUrl required for authorizationCode flow" unless config[:tokenUrl]
|
|
109
|
+
raise ArgumentError, "scopes required for authorizationCode flow" unless config[:scopes]
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
|
113
|
+
|
|
114
|
+
def flows_to_hash(flows)
|
|
115
|
+
result = {}
|
|
116
|
+
flows.each do |flow_type, config|
|
|
117
|
+
flow_hash = {}
|
|
118
|
+
flow_hash['authorizationUrl'] = config[:authorizationUrl] if config[:authorizationUrl]
|
|
119
|
+
flow_hash['tokenUrl'] = config[:tokenUrl] if config[:tokenUrl]
|
|
120
|
+
flow_hash['refreshUrl'] = config[:refreshUrl] if config[:refreshUrl]
|
|
121
|
+
scopes = config[:scopes]
|
|
122
|
+
flow_hash['scopes'] = scopes.respond_to?(:call) ? scopes.call : (scopes || {})
|
|
123
|
+
result[flow_type.to_s] = flow_hash
|
|
124
|
+
end
|
|
125
|
+
result
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module GrapeOpenapi
|
|
5
|
+
module Models
|
|
6
|
+
# https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#server-object
|
|
7
|
+
class Server
|
|
8
|
+
attr_reader :url, :description, :variables
|
|
9
|
+
|
|
10
|
+
def initialize(url:, description: nil, variables: nil)
|
|
11
|
+
@url = url
|
|
12
|
+
@description = description
|
|
13
|
+
@variables = variables
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def to_h
|
|
17
|
+
hash = { url: url }
|
|
18
|
+
hash[:description] = description if description.present?
|
|
19
|
+
hash[:variables] = variables_to_h if variables.present?
|
|
20
|
+
hash
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def variables_to_h
|
|
26
|
+
variables.transform_values(&:to_h)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module GrapeOpenapi
|
|
5
|
+
module Models
|
|
6
|
+
# https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#server-variable-object
|
|
7
|
+
class ServerVariable
|
|
8
|
+
attr_reader :default, :description, :enum
|
|
9
|
+
|
|
10
|
+
def initialize(default:, description: nil, enum: nil)
|
|
11
|
+
@default = default
|
|
12
|
+
@description = description
|
|
13
|
+
@enum = enum
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def to_h
|
|
17
|
+
hash = { default: default }
|
|
18
|
+
hash[:description] = description if description.present?
|
|
19
|
+
hash[:enum] = enum if enum.present?
|
|
20
|
+
hash
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module GrapeOpenapi
|
|
5
|
+
module Models
|
|
6
|
+
class Tag
|
|
7
|
+
def self.normalize_tag_name(tag_name)
|
|
8
|
+
name = tag_name.split('_').join(' ').capitalize
|
|
9
|
+
apply_overrides(name)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.apply_overrides(text)
|
|
13
|
+
overrides = Gitlab::GrapeOpenapi.configuration.tag_overrides
|
|
14
|
+
|
|
15
|
+
return text if overrides.nil? || overrides.empty?
|
|
16
|
+
|
|
17
|
+
pattern = Regexp.union(overrides.keys.map { |key| /\b#{Regexp.escape(key)}\b/i })
|
|
18
|
+
text.gsub(pattern) do |match|
|
|
19
|
+
overrides[match] || overrides[match.downcase] || overrides[match.capitalize] || match
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
attr_reader :name
|
|
24
|
+
|
|
25
|
+
def initialize(name)
|
|
26
|
+
@name = Gitlab::GrapeOpenapi::Models::Tag.normalize_tag_name(name)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def to_h
|
|
30
|
+
{
|
|
31
|
+
name: name,
|
|
32
|
+
description: description
|
|
33
|
+
}.compact
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def description
|
|
37
|
+
desc_name = name.downcase
|
|
38
|
+
desc_adjusted = self.class.apply_overrides(desc_name)
|
|
39
|
+
"Operations related to #{desc_adjusted}."
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'digest'
|
|
4
|
+
|
|
5
|
+
module Gitlab
|
|
6
|
+
module GrapeOpenapi
|
|
7
|
+
class RequestBodyRegistry
|
|
8
|
+
SCHEMA_PATH_PREFIX = '#/components/schemas/'
|
|
9
|
+
|
|
10
|
+
attr_reader :schemas
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
@schemas = {}
|
|
14
|
+
@schema_hashes = {}
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def register(schema)
|
|
18
|
+
return nil if schema.blank?
|
|
19
|
+
|
|
20
|
+
schema_hash = compute_hash(schema)
|
|
21
|
+
|
|
22
|
+
if @schema_hashes.key?(schema_hash)
|
|
23
|
+
existing_name = @schema_hashes[schema_hash]
|
|
24
|
+
return { '$ref' => "#{SCHEMA_PATH_PREFIX}#{existing_name}" }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
name = "RequestBody_#{short_hash(schema_hash)}"
|
|
28
|
+
@schemas[name] = schema
|
|
29
|
+
@schema_hashes[schema_hash] = name
|
|
30
|
+
|
|
31
|
+
{ '$ref' => "#{SCHEMA_PATH_PREFIX}#{name}" }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def compute_hash(schema)
|
|
37
|
+
normalized = normalize_for_hash(schema)
|
|
38
|
+
OpenSSL::Digest::SHA256.hexdigest(normalized.to_s)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def short_hash(full_hash)
|
|
42
|
+
full_hash[0, 12]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def normalize_for_hash(obj)
|
|
46
|
+
case obj
|
|
47
|
+
when Hash
|
|
48
|
+
obj.sort.map { |k, v| [k.to_s, normalize_for_hash(v)] }
|
|
49
|
+
when Array
|
|
50
|
+
obj.map { |v| normalize_for_hash(v) }
|
|
51
|
+
else
|
|
52
|
+
obj
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module GrapeOpenapi
|
|
5
|
+
class SchemaRegistry
|
|
6
|
+
attr_reader :schemas
|
|
7
|
+
|
|
8
|
+
def initialize
|
|
9
|
+
@schemas = {}
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def register(entity_class, schema)
|
|
13
|
+
normalized_name = normalize_entity_class(entity_class)
|
|
14
|
+
return normalized_name if @schemas.key?(normalized_name)
|
|
15
|
+
return normalized_name unless schema.is_a?(Models::Schema)
|
|
16
|
+
|
|
17
|
+
@schemas[normalized_name] = schema
|
|
18
|
+
normalized_name
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def normalize_entity_class(entity_class)
|
|
22
|
+
entity_class.name.delete(':')
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module GrapeOpenapi
|
|
5
|
+
module Serializers
|
|
6
|
+
class Time
|
|
7
|
+
DEFAULT_TIME = '2025-08-01T00:00:00.000Z'
|
|
8
|
+
|
|
9
|
+
def serialize(value, example: nil)
|
|
10
|
+
return unless defined?(ActiveSupport::TimeWithZone) && value.is_a?(ActiveSupport::TimeWithZone)
|
|
11
|
+
|
|
12
|
+
return example if example
|
|
13
|
+
|
|
14
|
+
DEFAULT_TIME
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Gitlab
|
|
4
|
+
module GrapeOpenapi
|
|
5
|
+
class TagRegistry
|
|
6
|
+
attr_reader :tags
|
|
7
|
+
|
|
8
|
+
def initialize
|
|
9
|
+
@tags = []
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def register(tag)
|
|
13
|
+
return if tag_exists?(tag)
|
|
14
|
+
|
|
15
|
+
tags << tag.to_h
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def to_h
|
|
19
|
+
{ tags: @tags }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def tag_exists?(tag)
|
|
25
|
+
tags.any? { |existing_tag| existing_tag[:name] == tag.name }
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "gitlab/grape_openapi/version"
|
|
4
|
+
require_relative "gitlab/grape_openapi/configuration"
|
|
5
|
+
require_relative "gitlab/grape_openapi/generator"
|
|
6
|
+
require_relative "gitlab/grape_openapi/schema_registry"
|
|
7
|
+
require_relative "gitlab/grape_openapi/request_body_registry"
|
|
8
|
+
require_relative "gitlab/grape_openapi/tag_registry"
|
|
9
|
+
|
|
10
|
+
# Concerns
|
|
11
|
+
require_relative "gitlab/grape_openapi/concerns/serializable"
|
|
12
|
+
require_relative "gitlab/grape_openapi/concerns/limit_resolver"
|
|
13
|
+
require_relative "gitlab/grape_openapi/concerns/fail_fast_annotatable"
|
|
14
|
+
require_relative "gitlab/grape_openapi/concerns/regex_converter"
|
|
15
|
+
|
|
16
|
+
# Serializers
|
|
17
|
+
require_relative "gitlab/grape_openapi/serializers/time"
|
|
18
|
+
|
|
19
|
+
# Converters
|
|
20
|
+
require_relative "gitlab/grape_openapi/converters/coercer_resolver"
|
|
21
|
+
require_relative "gitlab/grape_openapi/converters/entity_converter"
|
|
22
|
+
require_relative "gitlab/grape_openapi/converters/type_resolver"
|
|
23
|
+
require_relative "gitlab/grape_openapi/converters/tag_converter"
|
|
24
|
+
require_relative "gitlab/grape_openapi/converters/operation_converter"
|
|
25
|
+
require_relative "gitlab/grape_openapi/converters/path_converter"
|
|
26
|
+
require_relative "gitlab/grape_openapi/converters/parameter_converter"
|
|
27
|
+
require_relative "gitlab/grape_openapi/converters/response_converter"
|
|
28
|
+
require_relative "gitlab/grape_openapi/converters/request_body_converter"
|
|
29
|
+
|
|
30
|
+
# Models
|
|
31
|
+
require_relative "gitlab/grape_openapi/models/request_body/parameter_schema"
|
|
32
|
+
require_relative "gitlab/grape_openapi/models/request_body/parameters"
|
|
33
|
+
require_relative "gitlab/grape_openapi/models/schema"
|
|
34
|
+
require_relative "gitlab/grape_openapi/models/tag"
|
|
35
|
+
require_relative "gitlab/grape_openapi/models/server_variable"
|
|
36
|
+
require_relative "gitlab/grape_openapi/models/server"
|
|
37
|
+
require_relative "gitlab/grape_openapi/models/operation"
|
|
38
|
+
require_relative "gitlab/grape_openapi/models/path_item"
|
|
39
|
+
require_relative "gitlab/grape_openapi/models/response"
|
|
40
|
+
require_relative "gitlab/grape_openapi/models/security_scheme"
|
|
41
|
+
require_relative "gitlab/grape_openapi/models/info"
|
|
42
|
+
require_relative "gitlab/grape_openapi/models/parameter"
|
|
43
|
+
|
|
44
|
+
module Gitlab
|
|
45
|
+
module GrapeOpenapi
|
|
46
|
+
GenerationError = Class.new(StandardError)
|
|
47
|
+
|
|
48
|
+
class << self
|
|
49
|
+
attr_writer :configuration
|
|
50
|
+
|
|
51
|
+
def configuration
|
|
52
|
+
@configuration ||= Configuration.new
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def configure
|
|
56
|
+
yield(configuration)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def generate(options = {})
|
|
60
|
+
Generator.new(options).generate
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|