Skip to content

Fix Grape 3.2+ compatibility: desc kwargs, custom types, multi-type param recovery#978

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

Fix Grape 3.2+ compatibility: desc kwargs, custom types, multi-type param recovery#978
numbata wants to merge 11 commits into
masterfrom
worktree-fix+issue-977-desc-keyword-args

Conversation

@numbata

@numbata numbata commented May 17, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR brings grape-swagger into full compatibility with Grape 3.2 and beyond. It fixes two breaking changes introduced in Grape 3.2+ — the desc keyword-argument deprecation (which raises when Grape.deprecator.behavior = :raise) and the rejection of string type names and non-.parse custom types in params blocks — and adds recovery of type: [A, B] multi-type params, which Grape 3.2+ was serialising as a raw coercer string in swagger output instead of the declared type. The minimum Grape dependency is bumped to >= 2.1 (Grape 1.8 and 2.0 were already failing on Ruby 3.3+ due to an upstream Mustermann incompatibility), and the upper bound is expanded to < 5.0 to support Grape 4.x.

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).
  • Accept string-keyed api_documentation / specific_api_documentation hashes (e.g. loaded from YAML/JSON) via transform_keys(&:to_sym).
  • Accept :description as an alias for :desc; explicit desc: nil wins and does not fall through.

lib/grape-swagger/request_param_parsers/route.rb

  • Add collect_variant_types + extract_variant_validator_parts + restore_variant_type to recover the actual type list from VariantCollectionCoercer when Grape serialises type: [A, B] via #to_s. Grape 3.2+ stores validator metadata as Hash entries; older supported versions use CoerceValidator object instances — both shapes are handled.

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

  • Add def self.parse(val) = val to NestedModule::ApiResponse. Grape 3.2+ requires unknown types to satisfy Types.custom? (respond to .parse with arity 1); Grape::Entity already provides it so entity_parser.rb needs no change.

spec/swagger_v2/params_example_spec.rb

  • Move type: 'Object' from the Grape params declaration into documentation: { type: 'Object' }. Grape 3.2+ rejects string type names in params blocks; grape-swagger picks the type from the merged settings hash so swagger output is unchanged.

grape-swagger.gemspec

  • Bump minimum Grape to >= 2.1 (was >= 1.7); expand upper bound to < 5.0 (was < 4.0) to support Grape 4.x HEAD.

.github/workflows/ci.yml

  • Drop Grape 1.8.0 and 2.0.0 matrix rows (failing on Ruby 3.3+ upstream).
  • Add Ruby 3.2–3.4 × Grape 3.2.1 rows.
  • Drop ruby: '3.1', grape: '3.2.1' (Grape 3.2.1 requires Ruby >= 3.2).

.rubocop.yml

  • Disable Style/OneClassPerFilelib/grape-swagger.rb defines SwaggerRouting and SwaggerDocumentationAdder as separate top-level modules; moving them into the GrapeSwagger namespace would be a breaking change and will ship separately.

Gemfile

  • Add multi_json explicitly — required transitively by representable but not bundled on Ruby HEAD.

Validation

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

Tested against Grape 2.1.3, 2.2.0, 3.2.1, and HEAD.

Closes #977

@github-actions

github-actions Bot commented May 17, 2026

Copy link
Copy Markdown

Danger Report

No issues found.

View run

@numbata

numbata commented May 18, 2026

Copy link
Copy Markdown
Contributor Author

@dblock FYI, I’ll jump back into this and the other PRs in the my grape-review queue later today. It looks like we have everything we need to release the new minor version of the gem.

@dblock

dblock commented May 18, 2026

Copy link
Copy Markdown
Member

CI does need to be fixed

@dblock

dblock commented May 19, 2026

Copy link
Copy Markdown
Member

Since this breaks backwards compat, needs a version bump and an UPGRADING note. Check compatibility in README, too.

@numbata

numbata commented May 29, 2026

Copy link
Copy Markdown
Contributor Author

@moskvin Thanks for taking a look. I’ll combine this PR with yours for the next release. But as @dblock mentioned, there are still a few changes that should be made before merging, and I completely agree with that.

numbata added a commit that referenced this pull request May 31, 2026
Per maintainer feedback on PR #978, this release carries breaking
changes (Grape floor bump, `type: 'Object'` migration, custom-type
`parse` requirement) and therefore lands as 2.2.0, with a matching
UPGRADING entry and README compatibility-matrix row.

Docs
- README: add a `>= 2.2.0` compatibility row and cap the prior row at
  `< 2.2.0`. Document the new `:description` alias / string-keyed
  `api_documentation` affordance and the `:desc` precedence rule.
- UPGRADING: new "Upgrading to >= 2.2.0" section covering all three
  user-facing breaking changes (Grape floor, `type: 'Object'`, custom
  types needing `.parse`).
- CHANGELOG: split bullets into Breaking changes / Features / Fixes
  with accurate wording. Drop the misleading "matching the pre-keyword
  -args behaviour" framing — `:description` and string keys are new
  affordances. Add the custom-type `parse` requirement. Note that the
  variant-type recovery is a no-op on Grape < 3.3.

Code
- `pop_desc` is now private; it was an internal helper to `setup` but
  was leaking onto every `Grape::API` that mixed in `DocMethods`.
- `route.rb`: `flatten(1)` instead of unbounded `.flatten`, and skip
  the merge when the recovered coercer `@types` is empty so we don't
  overwrite the legacy serialisation with `[]`.

Tests
- Add regression coverage for the parts of `pop_desc` that the v2 fix
  was actually for: explicit `desc: nil` must not fall through to
  `:description`, and `specific_api_documentation: { description: ... }`
  goes through the second `pop_desc` call site too.

Public-API audit: `@converter` / `@types` (on VariantCollectionCoercer)
and `@scope` (on Validators::Base) have no public reader on the supported
Grape range (`scope` is private on HEAD and absent on 3.2.1), so the
`instance_variable_get` reaches remain — there is no stable public
alternative across the matrix.
@numbata numbata force-pushed the worktree-fix+issue-977-desc-keyword-args branch from 728e002 to a605502 Compare June 1, 2026 05:55

@dblock dblock left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM, merge at will

@numbata numbata force-pushed the worktree-fix+issue-977-desc-keyword-args branch from a605502 to 2c2bbe0 Compare June 22, 2026 06:14
@numbata numbata changed the title Fix Grape 3.2 compatibility: keyword args for desc and custom param types Fix Grape 3.2+ compatibility: desc kwargs, custom types, multi-type param recovery Jun 22, 2026
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)

3 participants