Class: Gitlab::GrapeOpenapi::Converters::ParameterConverter

Inherits:
Object
  • Object
show all
Includes:
Gitlab::GrapeOpenapi::Concerns::FailFastAnnotatable, Gitlab::GrapeOpenapi::Concerns::LimitResolver, Gitlab::GrapeOpenapi::Concerns::RegexConverter, Gitlab::GrapeOpenapi::Concerns::Serializable, CoercerResolver
Defined in:
lib/gitlab/grape_openapi/converters/parameter_converter.rb

Constant Summary

Constants included from Gitlab::GrapeOpenapi::Concerns::RegexConverter

Gitlab::GrapeOpenapi::Concerns::RegexConverter::JS_REGEX_TARGET

Constants included from Gitlab::GrapeOpenapi::Concerns::FailFastAnnotatable

Gitlab::GrapeOpenapi::Concerns::FailFastAnnotatable::FAIL_FAST_ANNOTATION

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Gitlab::GrapeOpenapi::Concerns::RegexConverter

#regexp_to_pattern

Methods included from CoercerResolver

#build_coerced_schema, #coercer_mapping_for

Constructor Details

#initialize(name, options:, validations:, route:) ⇒ ParameterConverter

Returns a new instance of ParameterConverter.



19
20
21
22
23
24
# File 'lib/gitlab/grape_openapi/converters/parameter_converter.rb', line 19

def initialize(name, options:, validations:, route:)
  @name = name
  @options = options
  @validations = validations
  @route = route # Useful for detecting `in` value.
end

Instance Attribute Details

#nameObject (readonly)

Returns the value of attribute name.



13
14
15
# File 'lib/gitlab/grape_openapi/converters/parameter_converter.rb', line 13

def name
  @name
end

#optionsObject (readonly)

Returns the value of attribute options.



13
14
15
# File 'lib/gitlab/grape_openapi/converters/parameter_converter.rb', line 13

def options
  @options
end

#routeObject (readonly)

Returns the value of attribute route.



13
14
15
# File 'lib/gitlab/grape_openapi/converters/parameter_converter.rb', line 13

def route
  @route
end

#validationsObject (readonly)

Returns the value of attribute validations.



13
14
15
# File 'lib/gitlab/grape_openapi/converters/parameter_converter.rb', line 13

def validations
  @validations
end

Class Method Details

.convert(name, options:, route:, validations: []) ⇒ Object



15
16
17
# File 'lib/gitlab/grape_openapi/converters/parameter_converter.rb', line 15

def self.convert(name, options:, route:, validations: [])
  new(name, options: options, validations: validations, route: route).convert
end

Instance Method Details

#add_regex_validations!(schema) ⇒ Object



126
127
128
129
130
131
132
133
134
135
# File 'lib/gitlab/grape_openapi/converters/parameter_converter.rb', line 126

def add_regex_validations!(schema)
  return unless validations

  # Only support one Regex validation per attribute
  validation = validations&.find { |v| v[:validator_class] == Grape::Validations::Validators::RegexpValidator }
  return unless validation

  pattern = regexp_to_pattern(validation[:options])
  schema[:pattern] = pattern if pattern
end

#array_type?(object_type) ⇒ Boolean

Returns:

  • (Boolean)


118
119
120
# File 'lib/gitlab/grape_openapi/converters/parameter_converter.rb', line 118

def array_type?(object_type)
  object_type.include?('[')
end

#build_array_schemaObject



97
98
99
100
# File 'lib/gitlab/grape_openapi/converters/parameter_converter.rb', line 97

def build_array_schema
  item_type = extract_array_item_type
  { type: 'array', items: { type: item_type } }
end

#build_basic_schema(object_type, object_format) ⇒ Object



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/gitlab/grape_openapi/converters/parameter_converter.rb', line 102

def build_basic_schema(object_type, object_format)
  schema = { type: object_type }
  schema[:format] = object_format if object_format
  if options[:default] && serializable?(options[:default])
    schema[:default] = options[:default]
  elsif options[:default] &&
      defined?(ActiveSupport::TimeWithZone) &&
      options[:default].is_a?(ActiveSupport::TimeWithZone)
    serialized_default = time_serializer.serialize(options[:default], example: example)
    schema[:default] = serialized_default if serialized_default
  end

  add_regex_validations!(schema)
  schema
end

#build_enum_schema(object_type) ⇒ Object



90
91
92
93
94
95
# File 'lib/gitlab/grape_openapi/converters/parameter_converter.rb', line 90

def build_enum_schema(object_type)
  schema = { type: object_type }
  schema[:enum] = options[:values] unless options[:values].is_a?(Proc)
  schema[:default] = options[:default] if options[:default] && serializable?(options[:default])
  schema
end

#build_range_schema(object_type) ⇒ Object



80
81
82
83
84
85
86
87
88
# File 'lib/gitlab/grape_openapi/converters/parameter_converter.rb', line 80

def build_range_schema(object_type)
  range = options[:values]
  schema = { type: object_type }

  schema[:minimum] = range.begin if range.begin
  schema[:maximum] = range.end if range.end
  schema[:default] = options[:default] if options[:default] && serializable?(options[:default])
  schema
end

#build_simple_array_schemaObject



67
68
69
70
# File 'lib/gitlab/grape_openapi/converters/parameter_converter.rb', line 67

def build_simple_array_schema
  item_type = options[:type].to_s.delete('[').delete(']')
  { type: 'array', items: { type: TypeResolver.resolve_type(item_type) } }
end

#build_union_schema(object_type) ⇒ Object



72
73
74
75
76
77
78
# File 'lib/gitlab/grape_openapi/converters/parameter_converter.rb', line 72

def build_union_schema(object_type)
  types = object_type[1..-2].split(", ")
  members = types.map { |type| TypeResolver.resolve_union_member(type) }
  apply_union_enum!(members)
  apply_union_default!(members)
  { oneOf: members }
end

#coercer_mappingObject



36
37
38
# File 'lib/gitlab/grape_openapi/converters/parameter_converter.rb', line 36

def coercer_mapping
  @coercer_mapping ||= coercer_mapping_for(validations)
end

#convertObject



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/gitlab/grape_openapi/converters/parameter_converter.rb', line 137

def convert
  # For requests that can have a request body (POST, PUT, PATCH, etc.), only return a param if it's in the path,
  # otherwise it'll be a body parameter and shouldn't be included as a query parameter.
  # GET and DELETE requests don't have request bodies, so all their parameters are included.
  method = route.request_method
  return nil if method != 'GET' && method != 'DELETE' && in_value != 'path'

  annotated = options.dup
  if options[:desc] && fail_fast_in_validations?(validations)
    annotated[:desc] = annotate_fail_fast(options[:desc])
  end

  param = Gitlab::GrapeOpenapi::Models::Parameter.new(
    name,
    options: annotated,
    schema: schema,
    in_value: in_value
  )

  mapping = coercer_mapping
  return param unless mapping

  param.style = mapping[:style] if mapping[:style]
  param.explode = mapping[:explode] if mapping.key?(:explode)
  param
end

#exampleObject



32
33
34
# File 'lib/gitlab/grape_openapi/converters/parameter_converter.rb', line 32

def example
  @options.dig(:documentation, :example)
end

#extract_array_item_typeObject



122
123
124
# File 'lib/gitlab/grape_openapi/converters/parameter_converter.rb', line 122

def extract_array_item_type
  options[:type].delete('[').delete(']').downcase
end

#in_valueObject



26
27
28
29
30
# File 'lib/gitlab/grape_openapi/converters/parameter_converter.rb', line 26

def in_value
  # Strip only the :version path segment (not substrings like :version_id or :package_version),
  # then match the param name as a complete segment bounded by / . ( or end-of-string.
  route.path.gsub('/:version/', '/').match?(%r{/:#{Regexp.escape(name)}([/.(]|$)}) ? 'path' : 'query'
end

#schemaObject



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/gitlab/grape_openapi/converters/parameter_converter.rb', line 40

def schema
  object_type = TypeResolver.resolve_type(options[:type]) || 'string'
  object_format = TypeResolver.resolve_format(nil, options[:type])
  type_str = options[:type].to_s

  mapping = coercer_mapping
  built_schema = if mapping
                   build_coerced_schema(mapping)
                 elsif type_str.start_with?('[') && type_str.exclude?(',')
                   build_simple_array_schema
                 elsif type_str.start_with?('[')
                   build_union_schema(object_type)
                 elsif options[:values].is_a?(Range)
                   build_range_schema(object_type)
                 elsif options[:values]
                   build_enum_schema(object_type)
                 elsif array_type?(object_type)
                   build_array_schema
                 else
                   build_basic_schema(object_type, object_format)
                 end

  apply_allow_blank(built_schema)
  apply_limit!(built_schema, validations)
  built_schema
end