use route tags for global tag set (#524)

* minor adoptions on README

* build global tag set from route tags
- adds changelog entry
- adds note in UPGRADING
This commit is contained in:
peter scholz 2016-10-23 19:45:33 +02:00 committed by GitHub
parent 14364e3c65
commit 7d405ff714
11 changed files with 128 additions and 125 deletions

View File

@ -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

View File

@ -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)
@ -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
@ -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.
@ -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
@ -591,8 +592,9 @@ end
}
```
<a name="array-type" />
#### Array type
#### Array of data type
Array types are also supported.

View File

@ -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:

View File

@ -50,7 +50,9 @@ module GrapeSwagger
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?

View File

@ -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

View File

@ -29,7 +29,6 @@ module Grape
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

View File

@ -118,91 +118,117 @@ describe 'swagger spec v2.0' do
end
end
before do
get '/v3/swagger_doc'
end
let(:json) { JSON.parse(last_response.body) }
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 }
describe 'whole documentation' do
subject do
get '/v3/swagger_doc'
JSON.parse(last_response.body)
end
describe 'info object required keys' do
let(:info) { json['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 'license object' do
let(:license) { json['info']['license'] }
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 }
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 'contact object' do
let(:contact) { json['info']['contact'] }
describe 'info object required keys' do
let(:info) { subject['info'] }
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
end
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 'path object' do
let(:paths) { json['paths'] }
describe 'license object' do
let(:license) { subject['info']['license'] }
it 'hides documentation paths per default' do
expect(paths.keys).not_to include '/swagger_doc', '/swagger_doc/{name}'
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 'contact object' do
let(:contact) { subject['info']['contact'] }
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 'global tags' do
let(:tags) { subject['tags'] }
it { expect(tags).to be_a Array }
it { expect(tags).not_to be_empty }
end
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
describe 'path object' do
let(:paths) { subject['paths'] }
value.each do |method, declaration|
expect(http_verbs).to include method
expect(declaration).to have_key('responses')
it 'hides documentation paths per default' do
expect(paths.keys).not_to include '/swagger_doc', '/swagger_doc/{name}'
end
declaration['responses'].each do |status_code, response|
expect(status_code).to match(/\d{3}/)
expect(response).to have_key('description')
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')
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
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 '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')
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

View File

@ -86,6 +86,7 @@ describe 'a guarded api endpoint' do
'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' => {

View File

@ -55,10 +55,7 @@ describe 'namespace tags check while using prefix and version' do
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' }
]
)
@ -75,10 +72,7 @@ describe 'namespace tags check while using prefix and version' do
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' }
]
)

View File

@ -48,10 +48,7 @@ describe 'namespace tags check' do
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' }
]
)
@ -68,10 +65,7 @@ describe 'namespace tags check' do
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' }
]
)

View File

@ -193,13 +193,7 @@ describe 'a simple mounted api' do
'produces' => ['application/xml', 'application/json', 'application/octet-stream', 'text/plain'],
'host' => 'example.org',
'tags' => [
{ 'name' => 'simple', 'description' => 'Operations about simples' },
{ 'name' => 'simple-test', 'description' => 'Operations about simple-tests' },
{ 'name' => 'simple-head-test', 'description' => 'Operations about simple-head-tests' },
{ 'name' => 'simple-options-test', 'description' => 'Operations about simple-options-tests' },
{ 'name' => 'simple_with_headers', 'description' => 'Operations about simple_with_headers' },
{ 'name' => 'items', 'description' => 'Operations about items' },
{ 'name' => 'custom', 'description' => 'Operations about customs' }
{ 'name' => 'simple', 'description' => 'Operations about simples' }
],
'paths' => {
'/simple' => {
@ -231,13 +225,7 @@ describe 'a simple mounted api' do
'produces' => ['application/xml', 'application/json', 'application/octet-stream', 'text/plain'],
'host' => 'example.org',
'tags' => [
{ 'name' => 'simple', 'description' => 'Operations about simples' },
{ 'name' => 'simple-test', 'description' => 'Operations about simple-tests' },
{ 'name' => 'simple-head-test', 'description' => 'Operations about simple-head-tests' },
{ 'name' => 'simple-options-test', 'description' => 'Operations about simple-options-tests' },
{ 'name' => 'simple_with_headers', 'description' => 'Operations about simple_with_headers' },
{ 'name' => 'items', 'description' => 'Operations about items' },
{ 'name' => 'custom', 'description' => 'Operations about customs' }
{ 'name' => 'simple-test', 'description' => 'Operations about simple-tests' }
],
'paths' => {
'/simple-test' => {