Class: Grape::Endpoint

Inherits:
Object
  • Object
show all
Defined in:
lib/grape-swagger/endpoint.rb

Constant Summary collapse

SUPPORTS_CONSUMES =
%i[post put patch].freeze

Instance Method Summary collapse

Instance Method Details

#add_definitions_from(models) ⇒ Object



90
91
92
93
94
# File 'lib/grape-swagger/endpoint.rb', line 90

def add_definitions_from(models)
  return if models.nil?

  models.each { |x| expose_params_from_model(x) }
end

#codes(route) ⇒ Object



245
246
247
248
249
# File 'lib/grape-swagger/endpoint.rb', line 245

def codes(route)
  http_codes_from_route(route).map do |x|
    x.is_a?(Array) ? { code: x[0], message: x[1], model: x[2], examples: x[3], headers: x[4] } : x
  end
end

#consumes_object(route, format) ⇒ Object



186
187
188
189
190
# File 'lib/grape-swagger/endpoint.rb', line 186

def consumes_object(route, format)
  return unless SUPPORTS_CONSUMES.include?(route.request_method.downcase.to_sym)

  GrapeSwagger::DocMethods::ProducesConsumes.call(route.settings.dig(:description, :consumes) || format)
end

#contact_object(infos) ⇒ Object

contact



70
71
72
73
74
75
76
# File 'lib/grape-swagger/endpoint.rb', line 70

def contact_object(infos)
  {
    name: infos.delete(:contact_name),
    email: infos.delete(:contact_email),
    url: infos.delete(:contact_url)
  }.delete_if { |_, value| value.blank? }
end

#content_types_for(target_class) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
# File 'lib/grape-swagger/endpoint.rb', line 9

def content_types_for(target_class)
  content_types = (target_class.content_types || {}).values

  if content_types.empty?
    formats       = [target_class.format, target_class.default_format].compact.uniq
    formats       = Grape::Formatter.formatters(**{}).keys if formats.empty?
    content_types = Grape::ContentTypes::CONTENT_TYPES.select do |content_type, _mime_type|
      formats.include? content_type
    end.values
  end

  content_types.uniq
end

#deprecated_object(route) ⇒ Object



147
148
149
# File 'lib/grape-swagger/endpoint.rb', line 147

def deprecated_object(route)
  route.options[:deprecated] if route.options.key?(:deprecated)
end

#description_object(route) ⇒ Object



163
164
165
166
167
168
# File 'lib/grape-swagger/endpoint.rb', line 163

def description_object(route)
  description = route.description if route.description.present?
  description = route.options[:detail] if route.options.key?(:detail)

  description
end

#http_codes_from_route(route) ⇒ Object



256
257
258
259
260
261
262
# File 'lib/grape-swagger/endpoint.rb', line 256

def http_codes_from_route(route)
  if route.http_codes.is_a?(Array) && route.http_codes.any? { |code| success_code?(code) }
    route.http_codes.clone
  else
    success_codes_from_route(route) + (route.http_codes || route.options[:failure] || [])
  end
end

#info_object(infos) ⇒ Object

building info object



45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/grape-swagger/endpoint.rb', line 45

def info_object(infos)
  result = {
    title: infos[:title] || 'API title',
    description: infos[:description],
    termsOfService: infos[:terms_of_service_url],
    contact: contact_object(infos),
    license: license_object(infos),
    version: infos[:version]
  }

  GrapeSwagger::DocMethods::Extensions.add_extensions_to_info(infos, result)

  result.delete_if { |_, value| value.blank? }
end

#license_object(infos) ⇒ Object

sub-objects of info object license



62
63
64
65
66
67
# File 'lib/grape-swagger/endpoint.rb', line 62

def license_object(infos)
  {
    name: infos.delete(:license),
    url: infos.delete(:license_url)
  }.delete_if { |_, value| value.blank? }
end

#method_object(route, options, path) ⇒ Object



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/grape-swagger/endpoint.rb', line 122

def method_object(route, options, path)
  method = {}
  method[:summary]     = summary_object(route)
  method[:description] = description_object(route)
  method[:produces]    = produces_object(route, options[:produces] || options[:format])
  method[:consumes]    = consumes_object(route, options[:consumes] || options[:format])
  method[:parameters]  = params_object(route, options, path, method[:consumes])
  # if any parameters are file type, automatically set consumes
  if method[:parameters].present? &&
     GrapeSwagger::DocMethods::FileParams.includes_file_param?(method[:parameters]) &&
     ['application/x-www-form-urlencoded', 'multipart/form-data'].none? do |consume|
       method[:consumes].include?(consume)
     end
    method[:consumes] = ['application/x-www-form-urlencoded', 'multipart/form-data']
  end
  method[:security]    = security_object(route)
  method[:responses]   = response_object(route, options)
  method[:tags]        = route.options.fetch(:tags, tag_object(route, path))
  method[:operationId] = GrapeSwagger::DocMethods::OperationId.build(route, path)
  method[:deprecated] = deprecated_object(route)
  method.delete_if { |_, value| value.nil? }

  [route.request_method.downcase.to_sym, method]
end

#params_object(route, options, path, consumes) ⇒ Object



192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/grape-swagger/endpoint.rb', line 192

def params_object(route, options, path, consumes)
  parameters = build_request_params(route, options).each_with_object([]) do |(param, value), memo|
    next if hidden_parameter?(value)

    value = { required: false }.merge(value) if value.is_a?(Hash)
    _, value = default_type([[param, value]]).first if value == ''

    if value.dig(:documentation, :type)
      expose_params(value[:documentation][:type])
    elsif value[:type]
      expose_params(value[:type])
    end
    memo << GrapeSwagger::DocMethods::ParseParams.call(param, value, path, route, @definitions, consumes)
  end

  if GrapeSwagger::DocMethods::FileParams.includes_file_param?(parameters)
    parameters = GrapeSwagger::DocMethods::FileParams.to_formdata(parameters)
  elsif GrapeSwagger::DocMethods::MoveParams.can_be_moved?(route.request_method, parameters)
    parameters = GrapeSwagger::DocMethods::MoveParams.to_definition(path, parameters, route, @definitions)
  end

  GrapeSwagger::DocMethods::FormatData.to_format(parameters)

  parameters.presence
end

#path_and_definition_objects(namespace_routes, options) ⇒ Object

building path and definitions objects



79
80
81
82
83
84
85
86
87
88
# File 'lib/grape-swagger/endpoint.rb', line 79

def path_and_definition_objects(namespace_routes, options)
  @paths = {}
  @definitions = {}
  add_definitions_from options[:models]
  namespace_routes.each_value do |routes|
    path_item(routes, options)
  end

  [@paths, @definitions]
end

#path_item(routes, options) ⇒ Object

path object



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/grape-swagger/endpoint.rb', line 97

def path_item(routes, options)
  operation_ids = {}
  routes.each do |route|
    next if hidden?(route, options)

    GrapeSwagger::DocMethods::PathString.generate_optional_segments(route.path.dup).each do |path|
      @item, path = GrapeSwagger::DocMethods::PathString.build(route, path, options)
      @entity = route.entity || route.options[:success]
      verb, method_object = method_object(route, options, path)
      if operation_ids.include?(method_object[:operationId])
        operation_ids[method_object[:operationId]] += 1
        method_object[:operationId] += operation_ids[method_object[:operationId]].to_s
      else
        operation_ids[method_object[:operationId]] = 1
      end
      if @paths.key?(path.to_s)
        @paths[path.to_s][verb] = method_object
      else
        @paths[path.to_s] = { verb => method_object }
      end
      GrapeSwagger::DocMethods::Extensions.add(@paths[path.to_s], @definitions, route)
    end
  end
end

#produces_object(route, format) ⇒ Object



170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/grape-swagger/endpoint.rb', line 170

def produces_object(route, format)
  return ['application/octet-stream'] if file_response?(route.attributes.success) &&
                                         !route.attributes.produces.present?

  mime_types = GrapeSwagger::DocMethods::ProducesConsumes.call(format)

  route_mime_types = %i[formats content_types produces].map do |producer|
    possible = route.options[producer]
    GrapeSwagger::DocMethods::ProducesConsumes.call(possible) if possible.present?
  end.flatten.compact.uniq

  route_mime_types.present? ? route_mime_types : mime_types
end

#response_object(route, options) ⇒ Object



218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/grape-swagger/endpoint.rb', line 218

def response_object(route, options)
  codes(route).each_with_object({}) do |value, memo|
    value[:message] ||= ''
    memo[value[:code]] = { description: value[:message] ||= '' } unless memo[value[:code]].present?
    memo[value[:code]][:headers] = value[:headers] if value[:headers]

    next build_file_response(memo[value[:code]]) if file_response?(value[:model])

    if memo.key?(200) && route.request_method == 'DELETE' && value[:model].nil?
      memo[204] = memo.delete(200)
      value[:code] = 204
      next
    end

    # Explicitly request no model with { model: '' }
    next if value[:model] == ''

    response_model = value[:model] ? expose_params_from_model(value[:model]) : @item
    next unless @definitions[response_model]
    next if response_model.start_with?('Swagger_doc')

    @definitions[response_model][:description] ||= "#{response_model} model"
    build_memo_schema(memo, route, value, response_model, options)
    memo[value[:code]][:examples] = value[:examples] if value[:examples]
  end
end

#security_object(route) ⇒ Object



151
152
153
# File 'lib/grape-swagger/endpoint.rb', line 151

def security_object(route)
  route.options[:security] if route.options.key?(:security)
end

#success_code?(code) ⇒ Boolean

Returns:

  • (Boolean)


251
252
253
254
# File 'lib/grape-swagger/endpoint.rb', line 251

def success_code?(code)
  status = code.is_a?(Array) ? code.first : code[:code]
  status.between?(200, 299)
end

#success_codes_from_route(route) ⇒ Object



264
265
266
267
268
269
270
271
272
# File 'lib/grape-swagger/endpoint.rb', line 264

def success_codes_from_route(route)
  if @entity.is_a?(Array)
    return @entity.map do |entity|
      success_code_from_entity(route, entity)
    end
  end

  [success_code_from_entity(route, @entity)]
end

#summary_object(route) ⇒ Object



155
156
157
158
159
160
161
# File 'lib/grape-swagger/endpoint.rb', line 155

def summary_object(route)
  summary = route.options[:desc] if route.options.key?(:desc)
  summary = route.description if route.description.present? && route.options.key?(:detail)
  summary = route.options[:summary] if route.options.key?(:summary)

  summary
end

#swagger_object(target_class, request, options) ⇒ Object

swagger spec2.0 related parts

required keys for SwaggerObject



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/grape-swagger/endpoint.rb', line 26

def swagger_object(target_class, request, options)
  object = {
    info: info_object(options[:info].merge(version: options[:doc_version])),
    swagger: '2.0',
    produces: options[:produces] || content_types_for(target_class),
    consumes: options[:consumes],
    authorizations: options[:authorizations],
    securityDefinitions: options[:security_definitions],
    security: options[:security],
    host: GrapeSwagger::DocMethods::OptionalObject.build(:host, options, request),
    basePath: GrapeSwagger::DocMethods::OptionalObject.build(:base_path, options, request),
    schemes: options[:schemes].is_a?(String) ? [options[:schemes]] : options[:schemes]
  }

  GrapeSwagger::DocMethods::Extensions.add_extensions_to_root(options, object)
  object.delete_if { |_, value| value.blank? }
end

#tag_object(route, path) ⇒ Object



274
275
276
277
278
279
280
281
282
283
# File 'lib/grape-swagger/endpoint.rb', line 274

def tag_object(route, path)
  version = GrapeSwagger::DocMethods::Version.get(route)
  version = Array(version)
  prefix = route.prefix.to_s.split('/').reject(&:empty?)
  Array(
    path.split('{')[0].split('/').reject(&:empty?).delete_if do |i|
      prefix.include?(i) || version.map(&:to_s).include?(i)
    end.first
  ).presence
end