Skip to content

Commit e2b50b3

Browse files
authored
Force request body to be an schema object (#922)
* Force request body to be an schema object * Require "OpenStruct" explicitly in specs * Update changelog and upgrading documentation
1 parent 262cdb9 commit e2b50b3

10 files changed

+132
-34
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#### Fixes
88

99
* Your contribution here.
10-
10+
* [#922](https://github.com/ruby-grape/grape-swagger/pull/922): Force request body to be an schema object - [@numbata](https://github.com/numbata)
1111

1212
### 2.0.2 (Februar 2, 2024)
1313

UPGRADING.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
## Upgrading Grape-swagger
22

3+
### Upgrading to >= x.y.z
4+
5+
- Grape-swagger now documents array parameters within an object schema in Swagger. This aligns with grape's JSON structure requirements and ensures the documentation is correct.
6+
- Previously, arrays were documented as standalone arrays, which could be incorrect based on grape's expectations.
7+
- Check your API documentation and update your code or tests that use the old array format.
8+
9+
Attention: This update may require you to make changes to ensure your API integrations continue to work correctly.
10+
For detailed reasons behind this update, refer to GitHub issue #666.
11+
312
### Upgrading to >= 1.5.0
413

514
- The names generated for body parameter definitions and their references has changed. It'll now include the HTTP action as well as any path parameters.

lib/grape-swagger/doc_methods/move_params.rb

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,30 +18,18 @@ def to_definition(path, params, route, definitions)
1818

1919
params_to_move = movable_params(params)
2020

21-
return (params + correct_array_param(params_to_move)) if should_correct_array?(params_to_move)
22-
2321
params << parent_definition_of_params(params_to_move, path, route)
2422

2523
params
2624
end
2725

2826
private
2927

30-
def should_correct_array?(param)
31-
param.length == 1 && param.first[:in] == 'body' && param.first[:type] == 'array'
32-
end
33-
34-
def correct_array_param(param)
35-
param.first[:schema] = { type: param.first.delete(:type), items: param.first.delete(:items) }
36-
37-
param
38-
end
39-
4028
def parent_definition_of_params(params, path, route)
4129
definition_name = OperationId.build(route, path)
42-
build_definition(definition_name, params)
30+
# NOTE: Parent definition is always object
31+
@definitions[definition_name] = object_type
4332
definition = @definitions[definition_name]
44-
4533
move_params_to_new(definition, params)
4634

4735
definition[:description] = route.description if route.try(:description)
@@ -53,6 +41,7 @@ def move_params_to_new(definition, params)
5341
params, nested_params = params.partition { |x| !x[:name].to_s.include?('[') }
5442
params.each do |param|
5543
property = param[:name]
44+
5645
param_properties, param_required = build_properties([param])
5746
add_properties_to_definition(definition, param_properties, param_required)
5847
related_nested_params, nested_params = nested_params.partition { |x| x[:name].start_with?("#{property}[") }

lib/grape-swagger/doc_methods/parse_params.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def document_add_extensions(settings)
7070

7171
def document_array_param(value_type, definitions)
7272
if value_type[:documentation].present?
73-
param_type = value_type[:documentation][:param_type]
73+
param_type = value_type[:documentation][:param_type] || value_type[:documentation][:in]
7474
doc_type = value_type[:documentation][:type]
7575
type = DataType.mapping(doc_type) if doc_type && !DataType.request_primitive?(doc_type)
7676
collection_format = value_type[:documentation][:collectionFormat]

spec/issues/539_array_post_body_spec.rb

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,19 +39,35 @@ class ArrayOfElements < Grape::Entity
3939
let(:definitions) { subject['definitions'] }
4040

4141
specify do
42-
expect(parameters).to eql(
42+
expect(parameters).to match(
4343
[
4444
{
45-
'in' => 'body', 'name' => 'elements', 'required' => true, 'schema' => {
46-
'type' => 'array', 'items' => { '$ref' => '#/definitions/Element' }
47-
}
45+
'name' => 'postIssue539',
46+
'required' => true,
47+
'in' => 'body',
48+
'schema' => { '$ref' => '#/definitions/postIssue539' }
4849
}
4950
]
5051
)
5152
end
5253

5354
specify do
54-
expect(definitions).to eql(
55+
expect(definitions).to include(
56+
'postIssue539' => {
57+
'description' => 'create account',
58+
'type' => 'object',
59+
'properties' => {
60+
'elements' => {
61+
'type' => 'array', 'items' => { '$ref' => '#/definitions/Element' }
62+
}
63+
},
64+
'required' => ['elements']
65+
}
66+
)
67+
end
68+
69+
specify do
70+
expect(definitions).to include(
5571
'Element' => {
5672
'type' => 'object',
5773
'properties' => {

spec/issues/542_array_of_type_in_post_body_spec.rb

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,37 @@
2525
end
2626

2727
let(:parameters) { subject['paths']['/issue_542']['post']['parameters'] }
28+
let(:definitions) { subject['definitions'] }
2829

2930
specify do
3031
expect(parameters).to eql(
3132
[
3233
{
3334
'in' => 'body',
34-
'name' => 'logs',
35+
'name' => 'postIssue542',
3536
'required' => true,
3637
'schema' => {
38+
'$ref' => '#/definitions/postIssue542'
39+
}
40+
}
41+
]
42+
)
43+
end
44+
45+
specify do
46+
expect(definitions).to include(
47+
'postIssue542' => {
48+
'type' => 'object',
49+
'properties' => {
50+
'logs' => {
3751
'type' => 'array',
3852
'items' => {
3953
'type' => 'string'
4054
}
4155
}
42-
}
43-
]
56+
},
57+
'required' => ['logs']
58+
}
4459
)
4560
end
4661
end

spec/issues/553_align_array_put_post_params_spec.rb

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -96,26 +96,38 @@
9696
describe 'in body' do
9797
describe 'post request' do
9898
let(:params) { subject['paths']['/in_body']['post']['parameters'] }
99+
let(:definitions) { subject['definitions'] }
99100

100101
specify do
101102
expect(params).to eql(
102103
[
103104
{
104105
'in' => 'body',
105-
'name' => 'guid',
106+
'name' => 'postInBody',
106107
'required' => true,
107-
'schema' => {
108+
'schema' => { '$ref' => '#/definitions/postInBody' }
109+
}
110+
]
111+
)
112+
expect(definitions).to include(
113+
'postInBody' => {
114+
'description' => 'create foo',
115+
'type' => 'object',
116+
'properties' => {
117+
'guid' => {
108118
'type' => 'array',
109119
'items' => { 'type' => 'string' }
110120
}
111-
}
112-
]
121+
},
122+
'required' => ['guid']
123+
}
113124
)
114125
end
115126
end
116127

117128
describe 'put request' do
118129
let(:params) { subject['paths']['/in_body/{id}']['put']['parameters'] }
130+
let(:definitions) { subject['definitions'] }
119131

120132
specify do
121133
expect(params).to eql(
@@ -128,14 +140,24 @@
128140
},
129141
{
130142
'in' => 'body',
131-
'name' => 'guid',
143+
'name' => 'putInBodyId',
132144
'required' => true,
133-
'schema' => {
145+
'schema' => { '$ref' => '#/definitions/putInBodyId' }
146+
}
147+
]
148+
)
149+
expect(definitions).to include(
150+
'putInBodyId' => {
151+
'description' => 'put specific foo',
152+
'type' => 'object',
153+
'properties' => {
154+
'guid' => {
134155
'type' => 'array',
135156
'items' => { 'type' => 'string' }
136157
}
137-
}
138-
]
158+
},
159+
'required' => ['guid']
160+
}
139161
)
140162
end
141163
end
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# frozen_string_literal: true
2+
3+
require 'spec_helper'
4+
5+
describe 'definition names' do
6+
before :all do
7+
module TestDefinition
8+
module Entity
9+
class Account < Grape::Entity
10+
expose :cma, documentation: { type: Integer, desc: 'Company number', param_type: 'body' }
11+
expose :name, documentation: { type: String, desc: 'Company Name' }
12+
expose :environment, documentation: { type: String, desc: 'Test Environment' }
13+
expose :sites, documentation: { type: Integer, desc: 'Amount of sites' }
14+
expose :username, documentation: { type: String, desc: 'Username for Dashboard' }
15+
expose :password, documentation: { type: String, desc: 'Password for Dashboard' }
16+
end
17+
18+
class Accounts < Grape::Entity
19+
expose :accounts, documentation: { type: Entity::Account, is_array: true, param_type: 'body', required: true }
20+
end
21+
end
22+
end
23+
end
24+
25+
let(:app) do
26+
Class.new(Grape::API) do
27+
namespace :issue_666 do
28+
desc 'createTestAccount',
29+
params: TestDefinition::Entity::Accounts.documentation
30+
post 'create' do
31+
present params
32+
end
33+
end
34+
35+
add_swagger_documentation format: :json
36+
end
37+
end
38+
39+
subject do
40+
get '/swagger_doc'
41+
JSON.parse(last_response.body)
42+
end
43+
44+
specify do
45+
expect(subject['definitions']['postIssue666Create']['type']).to eq('object')
46+
end
47+
end

spec/spec_helper.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
MODEL_PARSER = ENV.key?('MODEL_PARSER') ? ENV['MODEL_PARSER'].to_s.downcase.sub('grape-swagger-', '') : 'mock'
66

7+
require 'ostruct'
78
require 'grape'
89
require 'grape-swagger'
910

spec/swagger_v2/params_array_spec.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,7 @@
118118
end
119119

120120
specify do
121-
expect(subject['definitions']['postArrayOfType']['type']).to eql 'array'
122-
expect(subject['definitions']['postArrayOfType']['items']).to eql(
121+
expect(subject['definitions']['postArrayOfType']).to eql(
123122
'type' => 'object',
124123
'properties' => {
125124
'array_of_string' => {

0 commit comments

Comments
 (0)