Skip to content

Keep a :version path capture when the API declares no version - #2846

Open
ericproulx wants to merge 1 commit into
masterfrom
fix/route-param-named-version
Open

Keep a :version path capture when the API declares no version#2846
ericproulx wants to merge 1 commit into
masterfrom
fix/route-param-named-version

Conversation

@ericproulx

Copy link
Copy Markdown
Contributor

Summary

Grape::Request#make_params dropped :version from the routing args unconditionally, alongside :route_info:

filtered = routing_args&.except(:version, :route_info)

That is right when Grape put it there — a path-versioned API captures the version as a segment and exposes it through env['api.version'] rather than params. But it is not always Grape's. An API that declares no version can name a param :version:

class API < Grape::API
  format :json
  route_param :version do
    get { { v: params[:version] } }   # => {"v": null}
  end
end

GET /abc matched, Mustermann captured version => "abc", and the value was filtered out before the endpoint saw it — params[:version] nil and the key absent from params altogether. Same for a bare get '/:version'. A segment silently lost on a route that had matched.

API params[:version] before after
no version declared, route_param :version nil "abc"
no version declared, get '/:version' nil "abc"
version 'v1', using: :path absent (correct) absent
version 'v1', using: :header absent (correct) absent
version 'v1', using: :param absent (correct) absent

Approach

A route reports a #version only when the API declared one — Grape::Router::BaseRoute already delegates it to the pattern — so that distinguishes the two cases without any new API. Drop the capture when the route carries a version, keep it otherwise.

All three versioning strategies are unaffected: their routes report a version, so :version stays out of params and env['api.version'] remains the way to read it. A path-versioned API with a nested route_param :id still gets only id.

Backward compatibility

No UPGRADING entry. The change only adds a param that was being discarded, on APIs that declare no version — where nothing could have depended on it being absent, since the route matched but the value was unreachable.

request_spec.rb's "cuts version and route_info" asserted the old unconditional rule against a synthetic route_info; it now covers both branches with a route double that does and does not report a version.

Longstanding, not a regression: identical in 3.3.4.

Test plan

  • request_spec.rb split into version-carrying and version-less routes; verified the version-less case fails without the lib/ change.
  • Full RSpec suite passes locally (2544 examples, 0 failures).
  • RuboCop clean.
  • CI green.

🤖 Generated with Claude Code

Grape::Request#make_params dropped :version from the routing args
unconditionally, alongside :route_info. That is right when Grape put it
there -- a path-versioned API captures the version as a segment and exposes
it through env['api.version'] rather than params -- but it is not always
Grape's.

An API that declares no version can name a param :version:

    route_param :version do
      get { params[:version] }    # => nil
    end

The route matched and Mustermann captured the segment, but the value was
filtered out before the endpoint saw it, so params[:version] came back nil
and the key was absent from params entirely. Same for a bare
get '/:version'. Silent loss of a segment on a route that had matched.

A route reports a #version only when the API declared one, so use that to
tell the two apart: drop the capture when the route carries a version,
keep it otherwise. Path, header and param versioning are unaffected --
their routes all report a version, so :version stays out of params and
env['api.version'] remains the way to read it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@ericproulx
ericproulx force-pushed the fix/route-param-named-version branch from fe9290e to 09abf2b Compare August 1, 2026 11:52
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

Danger Report

Errors

  • One of the lines below found in CHANGELOG.md doesn't match the expected format. Please make it look like the other lines, pay attention to version numbers, periods, spaces and date formats.

Markdowns

* [#UUUU](https://github.com/ruby-grape/grape/pull/UUUU): Keep a `:version` path capture in `params` when the API declares no version, instead of always dropping it as Grape's own - [@ericproulx](https://github.com/ericproulx).
does not include a pull request link

View run

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

Danger Report

No issues found.

View run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant