Skip to content
Open
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#### Fixes

* [#986](https://github.com/ruby-grape/grape-swagger/pull/986): Read a route's tags through `route.tags` instead of `route.options`; `tags: nil` now means "not specified" and `tags: []` documents an endpoint with no tags. See [UPGRADING](UPGRADING.md) - [@ericproulx](https://github.com/ericproulx).
* Your contribution here.

### 2.2.0 (2026-08-06)
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,9 @@ end
Tags are used for logical grouping of operations by resources or any other qualifier. To override the
tags array, add `tags: ['tag1', 'tag2']` after the description.

When `tags:` is not given, the tag is derived from the path. Pass an empty array, `tags: []`, to
document the endpoint with no tags at all — the `tags` key is then left out of the operation.

```ruby
namespace 'order' do
desc 'This will be your summary', tags: ['orders']
Expand Down
6 changes: 6 additions & 0 deletions UPGRADING.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
## Upgrading Grape-swagger

### Upgrading to >= 2.3.0

- **`desc(..., tags: nil)` no longer suppresses the tag.** `nil` now means "not specified", as it does for every other `desc` option, so the tag is derived from the path as if `tags:` had been omitted. Use `tags: []` to document an endpoint with no tags — the `tags` key is then left out of the operation.

The old behaviour was never a deliberate one: [#523](https://github.com/ruby-grape/grape-swagger/pull/523) introduced route-level tags to *override* path-derived grouping and read them with `route.options.fetch(:tags, tag_object(route))`, whose default-on-absence semantics happened to give `nil` a meaning of its own. It was never documented or tested. `tags: []` says the same thing explicitly, and no longer emits a meaningless `"tags": []` into the document.

### Upgrading to >= 2.2.0

- **Minimum Grape version is now `>= 2.1`** (was `>= 1.7`). Grape 1.8.0 and 2.0.0 cannot be used on Ruby 3.3+ because of an upstream Mustermann/forwardable incompatibility; the CI rows for those combinations were already failing on `master` and have been removed.
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 @@ -123,7 +123,7 @@ def method_object(route, options, path)
method[:parameters] = params_object(route, options, path, method[:consumes])
method[:security] = security_object(route)
method[:responses] = response_object(route, options)
method[:tags] = route.options.key?(:tags) ? route.tags : tag_object(route, path)
method[:tags] = route.tags ? route.tags.presence : tag_object(route, path)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What’s the reason for using .presence here? If route.tags is absent, won’t the code go to the else branch anyway? 🤔

method[:operationId] = GrapeSwagger::DocMethods::OperationId.build(route, path)
method[:deprecated] = deprecated_object(route)
method.delete_if { |_, value| value.nil? }
Expand Down
23 changes: 21 additions & 2 deletions spec/swagger_v2/endpoint_versioned_path_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,25 @@
end
end

# An empty Array is the way to say "this endpoint has no tags"; nil means
# the option was not specified, as it does for every other desc option.
context 'when tags are explicitly empty' do
let(:item) do
Class.new(Grape::API) do
version 'v1', using: :path

resource :item do
desc 'Item description', tags: []
get '/'
end
end
end

it 'omits the tags key instead of documenting an empty list' do
expect(subject.first['/v1/item'][:get]).not_to have_key(:tags)
end
end

context 'when tags are explicitly set to nil' do
let(:item) do
Class.new(Grape::API) do
Expand All @@ -65,8 +84,8 @@
end
end

it 'omits the tags key instead of falling back to the default tag' do
expect(subject.first['/v1/item'][:get]).not_to have_key(:tags)
it 'falls back to the default tag' do
expect(subject.first['/v1/item'][:get][:tags]).to eq ['item']
end
end

Expand Down
Loading