Skip to content

Commit

Permalink
Include documented Hashes (#454)
Browse files Browse the repository at this point in the history
* Fix logic for mapping Hash and Array objects to refs

* Add tests to account for documented Hashes and Arrays

* Do not include readOnly params in request definitions

* Test for new documentation behavior

* Update changelog [ci skip]

* Use respond_to? instead of try for earlier compliance

* Use proper url for changelog
  • Loading branch information
aschuster3 authored and dblock committed Jun 14, 2016
1 parent 6ef800c commit 611572f
Show file tree
Hide file tree
Showing 12 changed files with 97 additions and 18 deletions.
9 changes: 6 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,17 @@
#### Features

* [#448](https://github.com/ruby-grape/grape-swagger/pull/448): Header parameters are now prepended to the parameter list - [@anakinj](https://github.com/anakinj).
* [#444](https://github.com/ruby-grape/grape-swagger/pull/444): With multi types parameter the first type is use as the documentation type [@scauglog](https://github.com/scauglog)
* [#444](https://github.com/ruby-grape/grape-swagger/pull/444): With multi types parameter the first type is use as the documentation type [@scauglog](https://github.com/scauglog).
* Your contribution here.

#### Fixes

* [#450](https://github.com/ruby-grape/grape-swagger/pull/438): Do not add :description to definitions if :description is missing on path - [@texpert](https://github.com/texpert).
* [#447](https://github.com/ruby-grape/grape-swagger/pull/447): Version part of the url is now ignored when generating tags for endpoint - [@anakinj](https://github.com/anakinj).
* [#444](https://github.com/ruby-grape/grape-swagger//pull/444): Default value provided in the documentation hash, override the grape default [@scauglog](https://github.com/scauglog)
* [#443](https://github.com/ruby-grape/grape-swagger/issues/443): Type provided in the documentation hash, override the grape type [@scauglog](https://github.com/scauglog)
* [#444](https://github.com/ruby-grape/grape-swagger//pull/444): Default value provided in the documentation hash, override the grape default [@scauglog](https://github.com/scauglog).
* [#443](https://github.com/ruby-grape/grape-swagger/issues/443): Type provided in the documentation hash, override the grape type [@scauglog](https://github.com/scauglog).
* [#454](https://github.com/ruby-grape/grape-swagger/pull/454): Include documented Hashes in documentation output - [@aschuster3](https://github.com/aschuster3).
* Your contribution here.

### 0.21.0 (June 1, 2016)

Expand Down
7 changes: 2 additions & 5 deletions lib/grape-swagger/doc_methods/move_params.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ def move_params_to_new(name, params)
end
end

properties[name][:readOnly] = true unless deletable?(param)
params.delete(param) if deletable?(param)

definition[:required] << name if deletable?(param) && param[:required]
Expand Down Expand Up @@ -144,13 +143,11 @@ def property_keys
end

def movable?(param)
return true if param[:in] == 'body' || param[:in] == 'path'
false
param[:in] == 'body'
end

def deletable?(param)
return true if movable?(param) && param[:in] == 'body'
false
param[:in] == 'body'
end

def should_move?(params)
Expand Down
2 changes: 1 addition & 1 deletion lib/grape-swagger/endpoint.rb
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ def parse_request_params(required)
else
key = param.first
end
memo[key] = param.last unless param.last[:type] == 'Hash' || param.last[:type] == 'Array' && !param.last.key?(:documentation)
memo[key] = param.last unless (param.last[:type] == 'Hash' || param.last[:type] == 'Array') && !param.last.key?(:documentation)
end
end

Expand Down
2 changes: 1 addition & 1 deletion spec/lib/move_params_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@
describe 'movable' do
describe 'path' do
let(:param) { { in: 'path', name: 'key', description: nil, type: 'integer', format: 'int32', required: true } }
it { expect(subject.send(:movable?, param)).to be true }
it { expect(subject.send(:movable?, param)).to be false }
end

describe 'body' do
Expand Down
8 changes: 7 additions & 1 deletion spec/support/model_parsers/entity_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ class RecursiveModel < Grape::Entity
expose :name, documentation: { type: String, desc: 'The name.' }
expose :children, using: self, documentation: { type: 'RecursiveModel', is_array: true, desc: 'The child nodes.' }
end

class DocumentedHashAndArrayModel < Grape::Entity
expose :raw_hash, documentation: { type: Hash, desc: 'Example Hash.', documentation: { in: 'body' } }
expose :raw_array, documentation: { type: Array, desc: 'Example Array', documentation: { in: 'body' } }
end
end
end

Expand All @@ -124,7 +129,8 @@ class RecursiveModel < Grape::Entity
'ApiError' => { 'type' => 'object', 'properties' => { 'code' => { 'type' => 'integer', 'format' => 'int32', 'description' => 'status code' }, 'message' => { 'type' => 'string', 'description' => 'error message' } } },
'ResponseItem' => { 'type' => 'object', 'properties' => { 'id' => { 'type' => 'integer', 'format' => 'int32' }, 'name' => { 'type' => 'string' } } },
'UseResponse' => { 'type' => 'object', 'properties' => { 'description' => { 'type' => 'string' }, '$responses' => { 'type' => 'array', 'items' => { '$ref' => '#/definitions/ResponseItem' } } } },
'RecursiveModel' => { 'type' => 'object', 'properties' => { 'name' => { 'type' => 'string', 'description' => 'The name.' }, 'children' => { 'type' => 'array', 'items' => { '$ref' => '#/definitions/RecursiveModel' }, 'description' => 'The child nodes.' } } }
'RecursiveModel' => { 'type' => 'object', 'properties' => { 'name' => { 'type' => 'string', 'description' => 'The name.' }, 'children' => { 'type' => 'array', 'items' => { '$ref' => '#/definitions/RecursiveModel' }, 'description' => 'The child nodes.' } } },
'DocumentedHashAndArrayModel' => { 'type' => 'object', 'properties' => { 'raw_hash' => { 'type' => 'object', 'description' => 'Example Hash.' }, 'raw_array' => { 'type' => 'array', 'description' => 'Example Array' } } }
}
end

Expand Down
10 changes: 10 additions & 0 deletions spec/support/model_parsers/mock_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ class QueryInput < OpenStruct; end
class ApiError < OpenStruct; end
class SecondApiError < OpenStruct; end
class RecursiveModel < OpenStruct; end
class DocumentedHashAndArrayModel < OpenStruct; end
end
end

Expand Down Expand Up @@ -83,6 +84,15 @@ class RecursiveModel < OpenStruct; end
'description' => "it's a mock"
}
}
},
'DocumentedHashAndArrayModel' => {
'type' => 'object',
'properties' => {
'mock_data' => {
'type' => 'string',
'description' => "it's a mock"
}
}
}
}
end
Expand Down
7 changes: 7 additions & 0 deletions spec/support/model_parsers/representable_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,13 @@ class RecursiveModel < Representable::Decorator
property :name, documentation: { type: String, desc: 'The name.' }
property :children, decorator: self, documentation: { type: 'RecursiveModel', is_array: true, desc: 'The child nodes.' }
end

class DocumentedHashAndArrayModel < Representable::Decorator
include Representable::JSON

property :raw_hash, documentation: { type: Hash, desc: 'Example Hash.' }
property :raw_array, documentation: { type: Array, desc: 'Example Array' }
end
end
end

Expand Down
3 changes: 1 addition & 2 deletions spec/support/the_paths_definitions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,7 @@
properties: {
in_body_1: { type: 'integer', format: 'int32', description: 'in_body_1' },
in_body_2: { type: 'string', description: 'in_body_2' },
in_body_3: { type: 'string', description: 'in_body_3' },
key: { type: 'integer', format: 'int32', readOnly: true }
in_body_3: { type: 'string', description: 'in_body_3' }
},
required: [:in_body_1]
}
Expand Down
3 changes: 2 additions & 1 deletion spec/swagger_v2/api_swagger_v2_definitions-models_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ class ModelApi < Grape::API
add_swagger_documentation models: [
::Entities::UseResponse,
::Entities::ApiError,
::Entities::RecursiveModel
::Entities::RecursiveModel,
::Entities::DocumentedHashAndArrayModel
]
end
end
Expand Down
60 changes: 60 additions & 0 deletions spec/swagger_v2/api_swagger_v2_hash_and_array_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
require 'spec_helper'

describe 'document hash and array' do
include_context "#{MODEL_PARSER} swagger example"

before :all do
module TheApi
class TestApi < Grape::API
format :json

documentation = ::Entities::DocumentedHashAndArrayModel.documentation if ::Entities::DocumentedHashAndArrayModel.respond_to?(:documentation)

desc 'This returns something'
namespace :arbitrary do
params do
requires :id, type: Integer
end
route_param :id do
desc 'Timeless treasure'
params do
requires :body, using: documentation unless documentation.nil?
requires :raw_hash, type: Hash, documentation: { param_type: 'body' } if documentation.nil?
requires :raw_array, type: Array, documentation: { param_type: 'body' } if documentation.nil?
end
put '/id_and_hash' do
{}
end
end
end

add_swagger_documentation
end
end
end

def app
TheApi::TestApi
end

subject do
get '/swagger_doc'
JSON.parse(last_response.body)
end
describe 'generated request definition' do
it 'has hash' do
expect(subject['definitions'].keys).to include('putArbitraryIdIdAndHash')
expect(subject['definitions']['putArbitraryIdIdAndHash']['properties'].keys).to include('raw_hash')
end

it 'has array' do
expect(subject['definitions'].keys).to include('putArbitraryIdIdAndHash')
expect(subject['definitions']['putArbitraryIdIdAndHash']['properties'].keys).to include('raw_array')
end

it 'does not have the path parameter' do
expect(subject['definitions'].keys).to include('putArbitraryIdIdAndHash')
expect(subject['definitions']['putArbitraryIdIdAndHash']).to_not include('id')
end
end
end
2 changes: 0 additions & 2 deletions spec/swagger_v2/api_swagger_v2_param_type_body_nested_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,6 @@ def app
'type' => 'object',
'properties' => {
'address' => { '$ref' => '#/definitions/putRequestUseNestedWithAddressAddress' },
'id' => { 'type' => 'integer', 'format' => 'int32', 'readOnly' => true },
'name' => { 'type' => 'string', 'description' => 'name' }
}
)
Expand Down Expand Up @@ -176,7 +175,6 @@ def app
'properties' => {
'address' => { '$ref' => '#/definitions/putRequestUseNestedWithAddressAddress' },
'delivery_address' => { '$ref' => '#/definitions/putRequestUseNestedWithAddressDeliveryAddress' },
'id' => { 'type' => 'integer', 'format' => 'int32', 'readOnly' => true },
'name' => { 'type' => 'string', 'description' => 'name' }
}
)
Expand Down
2 changes: 0 additions & 2 deletions spec/swagger_v2/api_swagger_v2_param_type_body_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ def app
'description' => 'put in body /wo entity',
'type' => 'object',
'properties' => {
'key' => { 'type' => 'integer', 'format' => 'int32', 'readOnly' => true },
'in_body_1' => { 'type' => 'integer', 'format' => 'int32', 'description' => 'in_body_1' },
'in_body_2' => { 'type' => 'string', 'description' => 'in_body_2' },
'in_body_3' => { 'type' => 'string', 'description' => 'in_body_3' }
Expand Down Expand Up @@ -152,7 +151,6 @@ def app
'description' => 'put in body with entity',
'type' => 'object',
'properties' => {
'id' => { 'type' => 'integer', 'format' => 'int32', 'readOnly' => true },
'name' => { 'type' => 'string', 'description' => 'name' }
}
)
Expand Down

0 comments on commit 611572f

Please sign in to comment.