Skip to content

Commit ac5ad64

Browse files
blakenumbata
authored andcommitted
Better implementation of request body
1 parent 48932a5 commit ac5ad64

File tree

7 files changed

+59
-37
lines changed

7 files changed

+59
-37
lines changed

lib/grape-swagger/openapi_3/endpoint.rb

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
require 'active_support'
44
require 'active_support/core_ext/string/inflections'
55
require 'grape-swagger/endpoint/params_parser'
6-
require 'grape-swagger/openapi_3/doc_methods/parse_request_body'
76

87
module Grape
98
class Endpoint
@@ -28,12 +27,17 @@ def swagger_object(_target_class, _request, options)
2827
object = {
2928
info: info_object(options[:info].merge(version: options[:doc_version])),
3029
openapi: '3.0.0',
31-
authorizations: options[:authorizations],
32-
securityDefinitions: options[:security_definitions],
3330
security: options[:security],
31+
authorizations: options[:authorizations],
3432
servers: options[:servers].is_a?(Hash) ? [options[:servers]] : options[:servers]
3533
}
3634

35+
if options[:security_definitions] || options[:security]
36+
components = { securitySchemes: options[:security_definitions] }
37+
components.delete_if { |_, value| value.blank? }
38+
object[:components] = components
39+
end
40+
3741
GrapeSwagger::DocMethods::Extensions.add_extensions_to_root(options, object)
3842
object.delete_if { |_, value| value.blank? }
3943
end
@@ -43,7 +47,7 @@ def info_object(infos)
4347
result = {
4448
title: infos[:title] || 'API title',
4549
description: infos[:description],
46-
termsOfServiceUrl: infos[:terms_of_service_url],
50+
termsOfService: infos[:terms_of_service_url],
4751
contact: contact_object(infos),
4852
license: license_object(infos),
4953
version: infos[:version]
@@ -123,7 +127,8 @@ def method_object(route, options, path)
123127
method[:parameters] = parameters.last
124128
method[:security] = security_object(route)
125129
if %w[POST PUT PATCH].include?(route.request_method)
126-
method[:requestBody] = response_body_object(route, path, parameters.first)
130+
consumes = consumes_object(route, options[:format])
131+
method[:requestBody] = response_body_object(route, path, consumes, parameters.first)
127132
end
128133

129134
produces = produces_object(route, options[:produces] || options[:format])
@@ -202,18 +207,23 @@ def params_object(route, options, path)
202207
parameters
203208
end
204209

205-
def response_body_object(_, _, parameters)
206-
parameters = {
207-
'content' => parameters.group_by { |p| p[:in] }.map do |_k, v|
208-
properties = v.map { |value| [value[:name], value.except(:name, :in, :required, :schema).merge(value[:schema])] }.to_h
209-
required_values = v.select { |param| param[:required] }.map { |required| required[:name] }
210-
result = { 'schema' => { 'type' => 'object', 'properties' => properties } }
211-
result['schema']['required'] = required_values unless required_values.empty?
212-
['application/x-www-form-urlencoded', result]
213-
end.to_h
214-
}
210+
def response_body_object(_, _, consumes, parameters)
211+
body_parameters, form_parameters = parameters.partition { |p| p[:in] == 'body' }
212+
result = consumes.map { |c| response_body_parameter_object(body_parameters, c) }
215213

216-
parameters
214+
unless form_parameters.empty?
215+
result << response_body_parameter_object(form_parameters, 'application/x-www-form-urlencoded')
216+
end
217+
218+
{ content: result.to_h }
219+
end
220+
221+
def response_body_parameter_object(parameters, content_type)
222+
properties = parameters.map { |value| [value[:name], value.except(:name, :in, :required, :schema).merge(value[:schema])] }.to_h
223+
required_values = parameters.select { |param| param[:required] }.map { |required| required[:name] }
224+
result = { schema: { type: :object, properties: properties } }
225+
result[:schema][:required] = required_values unless required_values.empty?
226+
[content_type, result]
217227
end
218228

219229
def response_object(route, content_types)
@@ -363,7 +373,7 @@ def expose_params_from_model(model)
363373
properties, required = parser.new(model, self).call
364374
unless properties&.any?
365375
raise GrapeSwagger::Errors::SwaggerSpec,
366-
"Empty model #{model_name}, swagger 2.0 doesn't support empty definitions."
376+
"Empty model #{model_name}, openapi 3.0 doesn't support empty definitions."
367377
end
368378

369379
@definitions[model_name] = GrapeSwagger::DocMethods::BuildModelDefinition.build(model, properties, required)

spec/openapi_3/form_params_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ def app
4747

4848
subject do
4949
get '/swagger_doc/items'
50-
puts last_response.body
5150
JSON.parse(last_response.body)
5251
end
5352

@@ -68,6 +67,7 @@ def app
6867
}]
6968

7069
expect(subject['paths']['/items/{id}']['post']['requestBody']).to eq 'content' => {
70+
'application/json' => { 'schema' => { 'properties' => {}, 'type' => 'object' } },
7171
'application/x-www-form-urlencoded' => {
7272
'schema' => {
7373
'properties' => {

spec/openapi_3/openapi_3_request_params_fix_spec.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,12 @@ def app
4848
specify do
4949
expect(subject['paths']['/bookings/{id}']['put']['parameters']).to eql(
5050
[
51-
{ 'in' => 'path', 'name' => 'id', 'schema' => { 'format' => 'int32', 'type' => 'integer' }, 'required' => true },
51+
{ 'in' => 'path', 'name' => 'id', 'schema' => { 'format' => 'int32', 'type' => 'integer' }, 'required' => true }
5252
]
5353
)
5454

5555
expect(subject['paths']['/bookings/{id}']['put']['requestBody']).to eql('content' => {
56+
'application/json' => { 'schema' => { 'properties' => {}, 'type' => 'object' } },
5657
'application/x-www-form-urlencoded' => {
5758
'schema' => {
5859
'properties' => { 'name' => { 'type' => 'string' } },

spec/openapi_3/param_multi_type_spec.rb

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,16 @@ def app
3030
end
3131

3232
it 'reads request body type correctly' do
33-
expect(subject['requestBody']['content']).to eq('application/x-www-form-urlencoded' => {
34-
'schema' => {
35-
'properties' => { 'another_input' => { 'type' => 'string' }, 'input' => { 'type' => 'string' } },
36-
'required' => %w[input another_input],
37-
'type' => 'object'
33+
expect(subject['requestBody']['content']).to eq(
34+
'application/json' => { 'schema' => { 'properties' => {}, 'type' => 'object' } },
35+
'application/x-www-form-urlencoded' => {
36+
'schema' => {
37+
'properties' => { 'another_input' => { 'type' => 'string' }, 'input' => { 'type' => 'string' } },
38+
'required' => %w[input another_input],
39+
'type' => 'object'
40+
}
3841
}
39-
})
42+
)
4043
end
4144

4245
describe 'header params' do

spec/openapi_3/param_type_spec.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ def app
3232

3333
it 'reads param type correctly' do
3434
expect(subject['requestBody']).to eq 'content' => {
35+
'application/json' => { 'schema' => { 'properties' => {}, 'type' => 'object' } },
3536
'application/x-www-form-urlencoded' => {
3637
'schema' => {
3738
'properties' => {
@@ -80,6 +81,7 @@ def app
8081

8182
it 'reads param type correctly' do
8283
expect(subject).to eq 'content' => {
84+
'application/json' => { 'schema' => { 'properties' => {}, 'type' => 'object' } },
8385
'application/x-www-form-urlencoded' => {
8486
'schema' => {
8587
'properties' => {

spec/openapi_3/params_hash_spec.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ def app
4242
specify do
4343
expect(subject['paths']['/use_groups']['post']).to include('requestBody')
4444
expect(subject['paths']['/use_groups']['post']['requestBody']['content']).to eql(
45+
'application/json' => { 'schema' => { 'properties' => {}, 'type' => 'object' } },
4546
'application/x-www-form-urlencoded' => {
4647
'schema' => {
4748
'properties' => {
@@ -65,6 +66,7 @@ def app
6566
specify do
6667
expect(subject['paths']['/use_given_type']['post']).to include('requestBody')
6768
expect(subject['paths']['/use_given_type']['post']['requestBody']['content']).to eql(
69+
'application/json' => { 'schema' => { 'properties' => {}, 'type' => 'object' } },
6870
'application/x-www-form-urlencoded' => {
6971
'schema' => {
7072
'properties' => {

spec/openapi_3/simple_mounted_api_spec.rb

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ def app
187187
'operationId' => 'postItems',
188188
'requestBody' => {
189189
'content' => {
190+
'application/json' => { 'schema' => { 'properties' => {}, 'type' => 'object' } },
190191
'application/x-www-form-urlencoded' => {
191192
'schema' => {
192193
'properties' => {
@@ -314,18 +315,21 @@ def app
314315
'post' => {
315316
'description' => 'this takes an array of parameters',
316317
'requestBody' => {
317-
'content' => { 'application/x-www-form-urlencoded' => {
318-
'schema' => {
319-
'properties' => {
320-
'items[]' => {
321-
'description' => 'array of items',
322-
'items' => { 'type' => 'string' },
323-
'type' => 'array'
324-
}
325-
},
326-
'type' => 'object'
318+
'content' => {
319+
'application/json' => { 'schema' => { 'properties' => {}, 'type' => 'object' } },
320+
'application/x-www-form-urlencoded' => {
321+
'schema' => {
322+
'properties' => {
323+
'items[]' => {
324+
'description' => 'array of items',
325+
'items' => { 'type' => 'string' },
326+
'type' => 'array'
327+
}
328+
},
329+
'type' => 'object'
330+
}
327331
}
328-
} }
332+
}
329333
},
330334
'tags' => ['items'],
331335
'operationId' => 'postItems',
@@ -339,11 +343,11 @@ def app
339343
describe 'supports custom params types' do
340344
subject do
341345
get '/swagger_doc/custom.json'
346+
raise('TODO: Fix')
342347
JSON.parse(last_response.body)
343348
end
344349

345350
specify do
346-
fail("TODO: Fix")
347351
expect(subject['paths']).to eq(
348352
'/custom' => {
349353
'get' => {

0 commit comments

Comments
 (0)