Skip to content

use route tags for global tag set #524

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 23, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@

#### Features

* [#524](https://github.com/ruby-grape/grape-swagger/pull/524): Use route tags for global tag set - [@LeFnord](https://github.com/LeFnord).
* [#523](https://github.com/ruby-grape/grape-swagger/pull/523): Allow specifying custom tags at the route level - [@jordanfbrown](https://github.com/jordanfbrown).
* [#520](https://github.com/ruby-grape/grape-swagger/pull/520): Response model can have required attributes - [@WojciechKo](https://github.com/WojciechKo).
* [#510](https://github.com/ruby-grape/grape-swagger/pull/510): Use 'token_owner' instead of 'oauth_token' on Swagger UI endpoint authorization. - [@texpert](https://github.com/texpert).
* [#523](https://github.com/ruby-grape/grape-swagger/pull/523): Allow specifying custom tags at the route level. - [@jordanfbrown](https://github.com/jordanfbrown).
* Your contribution here.

#### Fixes
Expand Down
24 changes: 13 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -394,10 +394,10 @@ add_swagger_documentation \
* [Overriding the tags](#tags)
* [Defining an endpoint as an array](#array)
* [Using an options hash](#options)
* [Overriding param type](#overriding-param-type)
* [Overriding param types](#overriding-param-types)
* [Multiple param types](#multiple-types)
* [Array type](#array-type)
* [Overriding parameter type](#overriding-param-type)
* [Overriding data type of the parameter](#overriding-type-of-param)
* [Multiple types](#multiple-types)
* [Array of data type](#array-type)
* [Collection Format](#collection-format)
* [Hiding parameters](#hiding-parameters)
* [Setting a Swagger default value](#default-value)
Expand Down Expand Up @@ -530,9 +530,9 @@ get '/kittens' do


<a name="overriding-param-type" />
#### Overriding param type
#### Overriding parameter type

You can override paramType in POST|PUT methods to query, using the documentation hash.
You can override paramType, using the documentation hash. See [parameter object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#parameter-object) for available types.

```ruby
params do
Expand All @@ -543,8 +543,9 @@ post :act do
end
```

<a name="overriding-param-types" />
#### Overriding param types

<a name="overriding-type-of-param" />
#### Overriding data type of the parameter

You can override type, using the documentation hash.

Expand All @@ -569,9 +570,9 @@ end


<a name="multiple-types" />
#### Multi types
#### Multiple types

By default when you set multi types, the first type is selected as swagger type
By default when you set multiple types, the first type is selected as swagger type

```ruby
params do
Expand All @@ -591,8 +592,9 @@ end
}
```


<a name="array-type" />
#### Array type
#### Array of data type

Array types are also supported.

Expand Down
4 changes: 4 additions & 0 deletions UPGRADING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
Upgrading Grape-swagger
=======================

### Upgrading to >= 0.25.0

The global tag set now only includes tags for documented routes. This behaviour has impact in particular for calling the documtation of a specific route.

### Upgrading to >= 0.21.0

With grape >= 0.21.0, `grape-entity` support moved to separate gem `grape-swagger-entity`, if you use grape entity, update your Gemfile:
Expand Down
4 changes: 3 additions & 1 deletion lib/grape-swagger/doc_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ def setup(options)
options
)

paths, definitions = endpoint.path_and_definition_objects(combi_routes, options)
paths, definitions = endpoint.path_and_definition_objects(combi_routes, options)
tags = GrapeSwagger::DocMethods::TagNameDescription.build(paths)
output[:tags] = tags unless tags.empty? || paths.blank?
output[:paths] = paths unless paths.blank?
output[:definitions] = definitions unless definitions.blank?

Expand Down
26 changes: 9 additions & 17 deletions lib/grape-swagger/doc_methods/tag_name_description.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,15 @@ module GrapeSwagger
module DocMethods
class TagNameDescription
class << self
def build(options = {})
target_class = options[:target_class]
namespaces = target_class.combined_namespaces
namespace_routes = target_class.combined_namespace_routes

namespace_routes.keys.map do |local_route|
next if namespace_routes[local_route].map { |route| route.options[:hidden] }.all? { |value| value.respond_to?(:call) ? value.call : value }

original_namespace_name = target_class.combined_namespace_identifiers.key?(local_route) ? target_class.combined_namespace_identifiers[local_route] : local_route
description = namespaces[original_namespace_name] && namespaces[original_namespace_name].options[:desc]
description ||= "Operations about #{original_namespace_name.pluralize}"

{
name: local_route,
description: description
}
end.compact
def build(paths)
paths.values.each_with_object([]) do |path, memo|
path.values.first[:tags].each do |tag|
memo << {
name: tag,
description: "Operations about #{tag.pluralize}"
}
end
end.uniq
end
end
end
Expand Down
1 change: 0 additions & 1 deletion lib/grape-swagger/endpoint.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ def swagger_object(target_class, request, options)
securityDefinitions: options[:security_definitions],
host: GrapeSwagger::DocMethods::OptionalObject.build(:host, options, request),
basePath: GrapeSwagger::DocMethods::OptionalObject.build(:base_path, options, request),
tags: GrapeSwagger::DocMethods::TagNameDescription.build(options),
schemes: options[:schemes].is_a?(String) ? [options[:schemes]] : options[:schemes]
}.delete_if { |_, value| value.blank? }
end
Expand Down
148 changes: 87 additions & 61 deletions spec/swagger_v2/api_swagger_v2_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,91 +118,117 @@ def app
end
end

before do
get '/v3/swagger_doc'
end
describe 'whole documentation' do
subject do
get '/v3/swagger_doc'
JSON.parse(last_response.body)
end

let(:json) { JSON.parse(last_response.body) }
describe 'swagger object' do
describe 'required keys' do
it { expect(subject.keys).to include 'swagger' }
it { expect(subject['swagger']).to eql '2.0' }
it { expect(subject.keys).to include 'info' }
it { expect(subject['info']).to be_a Hash }
it { expect(subject.keys).to include 'paths' }
it { expect(subject['paths']).to be_a Hash }
end

describe 'swagger object' do
describe 'required keys' do
it { expect(json.keys).to include 'swagger' }
it { expect(json['swagger']).to eql '2.0' }
it { expect(json.keys).to include 'info' }
it { expect(json['info']).to be_a Hash }
it { expect(json.keys).to include 'paths' }
it { expect(json['paths']).to be_a Hash }
end
describe 'info object required keys' do
let(:info) { subject['info'] }

it { expect(info.keys).to include 'title' }
it { expect(info['title']).to be_a String }
it { expect(info.keys).to include 'version' }
it { expect(info['version']).to be_a String }

describe 'info object required keys' do
let(:info) { json['info'] }
describe 'license object' do
let(:license) { subject['info']['license'] }

it { expect(info.keys).to include 'title' }
it { expect(info['title']).to be_a String }
it { expect(info.keys).to include 'version' }
it { expect(info['version']).to be_a String }
it { expect(license.keys).to include 'name' }
it { expect(license['name']).to be_a String }
it { expect(license.keys).to include 'url' }
it { expect(license['url']).to be_a String }
end

describe 'license object' do
let(:license) { json['info']['license'] }
describe 'contact object' do
let(:contact) { subject['info']['contact'] }

it { expect(license.keys).to include 'name' }
it { expect(license['name']).to be_a String }
it { expect(license.keys).to include 'url' }
it { expect(license['url']).to be_a String }
end
it { expect(contact.keys).to include 'name' }
it { expect(contact['name']).to be_a String }
it { expect(contact.keys).to include 'email' }
it { expect(contact['email']).to be_a String }
it { expect(contact.keys).to include 'url' }
it { expect(contact['url']).to be_a String }
end

describe 'contact object' do
let(:contact) { json['info']['contact'] }
describe 'global tags' do
let(:tags) { subject['tags'] }

it { expect(contact.keys).to include 'name' }
it { expect(contact['name']).to be_a String }
it { expect(contact.keys).to include 'email' }
it { expect(contact['email']).to be_a String }
it { expect(contact.keys).to include 'url' }
it { expect(contact['url']).to be_a String }
it { expect(tags).to be_a Array }
it { expect(tags).not_to be_empty }
end
end
end

describe 'path object' do
let(:paths) { json['paths'] }
describe 'path object' do
let(:paths) { subject['paths'] }

it 'hides documentation paths per default' do
expect(paths.keys).not_to include '/swagger_doc', '/swagger_doc/{name}'
end
it 'hides documentation paths per default' do
expect(paths.keys).not_to include '/swagger_doc', '/swagger_doc/{name}'
end

specify do
paths.each_pair do |path, value|
expect(path).to start_with('/')
expect(value).to be_a Hash
expect(value).not_to be_empty
specify do
paths.each_pair do |path, value|
expect(path).to start_with('/')
expect(value).to be_a Hash
expect(value).not_to be_empty

value.each do |method, declaration|
expect(http_verbs).to include method
expect(declaration).to have_key('responses')
value.each do |method, declaration|
expect(http_verbs).to include method
expect(declaration).to have_key('responses')

declaration['responses'].each do |status_code, response|
expect(status_code).to match(/\d{3}/)
expect(response).to have_key('description')
declaration['responses'].each do |status_code, response|
expect(status_code).to match(/\d{3}/)
expect(response).to have_key('description')
end
end
end
end
end
end

describe 'definitions object' do
let(:definitions) { json['definitions'] }
specify do
definitions.each do |model, properties|
expect(model).to match(/\w+/)
expect(properties).to have_key('properties')
describe 'definitions object' do
let(:definitions) { subject['definitions'] }

specify do
definitions.each do |model, properties|
expect(model).to match(/\w+/)
expect(properties).to have_key('properties')
end
end
end
end

describe 'swagger file' do
it do
expect(subject).to eql swagger_json
end
end
end

describe 'swagger file' do
it do
expect(json).to eql swagger_json
describe 'specific resource documentation' do
subject do
get '/v3/swagger_doc/other_thing'
JSON.parse(last_response.body)
end

let(:tags) { subject['tags'] }
specify do
expect(tags).to eql [
{
'name' => 'other_thing',
'description' => 'Operations about other_things'
}
]
end
end
end
1 change: 1 addition & 0 deletions spec/swagger_v2/guarded_endpoint_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ def app
'swagger' => '2.0',
'produces' => ['application/xml', 'application/json', 'application/octet-stream', 'text/plain'],
'host' => 'example.org',
'tags' => [{ 'name' => 'auth', 'description' => 'Operations about auths' }],
'paths' => {
'/auth' => {
'get' => {
Expand Down
10 changes: 2 additions & 8 deletions spec/swagger_v2/namespace_tags_prefix_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,7 @@ def app
specify do
expect(subject['tags']).to eql(
[
{ 'name' => 'hudson', 'description' => 'Operations about hudsons' },
{ 'name' => 'colorado', 'description' => 'Operations about colorados' },
{ 'name' => 'thames', 'description' => 'Operations about thames' },
{ 'name' => 'niles', 'description' => 'Operations about niles' }
{ 'name' => 'colorado', 'description' => 'Operations about colorados' }
]
)

Expand All @@ -75,10 +72,7 @@ def app
specify do
expect(subject['tags']).to eql(
[
{ 'name' => 'hudson', 'description' => 'Operations about hudsons' },
{ 'name' => 'colorado', 'description' => 'Operations about colorados' },
{ 'name' => 'thames', 'description' => 'Operations about thames' },
{ 'name' => 'niles', 'description' => 'Operations about niles' }
{ 'name' => 'thames', 'description' => 'Operations about thames' }
]
)

Expand Down
10 changes: 2 additions & 8 deletions spec/swagger_v2/namespace_tags_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,7 @@ def app
specify do
expect(subject['tags']).to eql(
[
{ 'name' => 'hudson', 'description' => 'Operations about hudsons' },
{ 'name' => 'colorado', 'description' => 'Operations about colorados' },
{ 'name' => 'thames', 'description' => 'Operations about thames' },
{ 'name' => 'niles', 'description' => 'Operations about niles' }
{ 'name' => 'colorado', 'description' => 'Operations about colorados' }
]
)

Expand All @@ -68,10 +65,7 @@ def app
specify do
expect(subject['tags']).to eql(
[
{ 'name' => 'hudson', 'description' => 'Operations about hudsons' },
{ 'name' => 'colorado', 'description' => 'Operations about colorados' },
{ 'name' => 'thames', 'description' => 'Operations about thames' },
{ 'name' => 'niles', 'description' => 'Operations about niles' }
{ 'name' => 'thames', 'description' => 'Operations about thames' }
]
)

Expand Down
Loading