Skip to content

documentation: { hidden: true } on a Hash parameter doesn't hide its nested query parameters #1015

Closed

Description

@seriousdev-gh

When a hash parameter is hidden from the documentation, its nested children are
still emitted as separate parent[child] query parameters, referencing a
parameter that no longer exists in the document.

Reproduction

require 'logger' # only needed in a bare script with activesupport 6.1 on Ruby 3.x
require 'grape'
require 'grape-swagger'
require 'rack/test'
require 'json'

class API < Grape::API
  format :json

  params do
    optional :query, type: String
    optional :filters, type: Hash, documentation: { hidden: true } do
      optional :status, type: String
      optional :kind, type: String
    end
  end
  get('/search') { 'ok' }

  add_swagger_documentation
end

include Rack::Test::Methods

def app
  API
end

get '/swagger_doc'
names = JSON.parse(last_response.body).dig('paths', '/search', 'get', 'parameters').map { _1['name'] }
puts names.inspect

Actual / Expected

actual:   ["query", "filters[status]", "filters[kind]"]   # verified, grape-swagger 2.1.1
expected: ["query"]

Cause

Grape::Endpoint#params_object (reopened by grape-swagger, endpoint.rb) checks
hidden_parameter? per entry of build_request_params. Nested params arrive as
separate entries (filters[status], …) whose options don't carry the parent's
documentation, so the parent's hidden: true is never considered for them
(and the container entry itself is dropped, leaving orphaned children).
Verified on v2.1.1; the same code path is present in v2.2.0 (endpoint.rb and
RequestParamParsers::Route). We currently work around it by prepending a
module to Grape::Endpoint that rejects parent[child] entries whose parent is
marked hidden in route.params — happy to PR that as a fix if the approach
fits (note: may overlap with #999).

Activity

  1. numbata commented on Nov 4, 2026

    @numbata
    Contributor

    @seriousdev-gh Thanks for the report, confirmed. Fixed in #1016: children of a hidden parent are now skipped at any depth, and siblings like filters_extra are unaffected. It also makes the parameter-level hidden: proc receive the token_owner, as the route-level one already does. That used to raise ArgumentError.

  2. added a commit that references this issue on Nov 8, 2026
    d2d6d4d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions