Skip to content

Fix Grape 3.2 compatibility: keyword args for desc and custom param types#978

Open
numbata wants to merge 4 commits into
masterfrom
worktree-fix+issue-977-desc-keyword-args
Open

Fix Grape 3.2 compatibility: keyword args for desc and custom param types#978
numbata wants to merge 4 commits into
masterfrom
worktree-fix+issue-977-desc-keyword-args

Conversation

@numbata
Copy link
Copy Markdown
Contributor

@numbata numbata commented May 17, 2026

Summary

Grape 3.2 introduces two breaking changes that cause add_swagger_documentation to raise when Grape.deprecator.behavior = :raise (the default in Grape's own CI). First, desc emits a deprecation when called with a positional options Hash; grape-swagger called it that way in two places in doc_methods.rb. Second, optional/requires now routes :type through Grape's dry-types coercion infrastructure, which rejects plain string type names (e.g. 'Object') and unknown classes that don't implement .parse. This PR fixes both issues and documents the 'Object' type pattern for future maintainers.

Changes

lib/grape-swagger/doc_methods.rb

  • Pass keyword arguments to both desc calls so Grape's deprecator does not fire (or raise when behavior = :raise).

spec/support/model_parsers/mock_parser.rb and representable_parser.rb

  • Add def self.parse(val) = val to NestedModule::ApiResponse in both parsers. Grape 3.2+ requires unknown types used in params blocks to satisfy Types.custom? (i.e. respond to .parse with arity 1), otherwise it attempts a dry-types lookup that raises ArgumentError. Grape::Entity already implements .parse, so entity_parser.rb needs no change. The implementation is intentionally minimal — these specs test swagger documentation generation only, not request coercion.

spec/swagger_v2/params_example_spec.rb

  • Move type: 'Object' from the Grape params declaration into documentation: { type: 'Object' }. 'Object' is not a valid Grape coercion type; it is a swagger documentation hint. Grape 3.2+ rejects string type names in params blocks. grape-swagger picks up the type from the merged settings hash in ParseParams#call, so the swagger output is unchanged. A comment in the spec explains the pattern.

.rubocop_todo.yml

  • Suppress Style/OneClassPerFile for lib/grape-swagger.rb and two spec files where multiple top-level modules are a pre-existing condition. Moving SwaggerRouting and SwaggerDocumentationAdder inside the GrapeSwagger namespace would be a breaking change for dependent gems referencing those constants; that rename will ship separately.

Validation — all three MODEL_PARSER values

MODEL_PARSER Examples Failures
mock (default) 478 0
grape-swagger-entity 478 0
grape-swagger-representable 478 0

Tested against Grape 3.2.1 (the version in this worktree's Gemfile.lock).

Closes #977

numbata added 4 commits May 17, 2026 10:38
Grape 3.2.1 deprecates passing a positional options Hash to `desc` and
requires unknown types in params blocks to either be a registered dry-type
or implement `parse` (custom type protocol). This change addresses both.

- Pass keyword arguments to `desc` in doc_methods.rb so Grape's deprecator
  does not fire (or raise when behavior = :raise)
- Add `self.parse` to the mock `Entities::NestedModule::ApiResponse` so
  Grape treats it as a custom type instead of attempting a dry-types lookup
- Move `type: 'Object'` into the `documentation` hash in params_example_spec
  so Grape no longer sees an unknown string type; grape-swagger still reads
  it from the merged settings and emits the expected swagger output
Moving SwaggerRouting and SwaggerDocumentationAdder inside the GrapeSwagger
namespace would be a breaking change for dependent gems that reference these
constants by their top-level names. Exclude the affected files in
.rubocop_todo.yml to keep CI green until that rename ships separately.
Add comments explaining:
- 'Object' is a swagger documentation hint, not a valid Grape coercion type;
  the type lives in documentation: so grape-swagger picks it up via settings merge
- ApiResponse.parse is required because Grape 3.2+ validates unknown types via
  Types.custom? (arity-1 parse check); minimal pass-through is sufficient since
  tests exercise documentation generation, not request coercion
Representable::Decorator does not implement .parse, so Grape 3.2+ raises
ArgumentError when ApiResponse is used as a param type. Same fix as mock_parser.
@github-actions
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.

Grape deprecates passing a positional options Hash to desc (grape-swagger uses it internally)

1 participant