Compare the base API, not to_s, when refreshing a mounted app#2788
Open
ericproulx wants to merge 1 commit into
Open
Compare the base API, not to_s, when refreshing a mounted app#2788ericproulx wants to merge 1 commit into
ericproulx wants to merge 1 commit into
Conversation
`refresh_already_mounted` deduplicates endpoints for the "same" mounted app by comparing `endpoint.mounted_app.to_s == app.to_s`. That only works by accident: `mount` turns every mounted Grape API into a throwaway `mount_instance` (a fresh `Class.new(@base_parent)` per mount), so two mounts of the same API are distinct objects, and `Grape::API::Instance` delegates `to_s` to its `@base` (the original API). The comparison is really "same base API", done through a string proxy -- brittle (two APIs that happen to share a name collide) and unclear. Expose the base API via a reader and compare it by identity instead. Plain Rack apps have no base and are mounted as-is, so they fall back to object identity. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
90344ff to
0aee2c2
Compare
Danger ReportNo issues found. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
refresh_already_mounteddeduplicates endpoints for the "same" mounted app with a string compare:This only works by accident.
mountturns every mounted Grape API into a throwawaymount_instance, andmount_instancebuilds a freshClass.new(@base_parent)on every call (lib/grape/api.rb), so two mounts of the same API are distinct objects —app == mounted_appis alwaysfalse. What makes the.to_scompare land is thatGrape::API::Instancedelegatesto_sto its@base(the original API):So
mounted_app.to_s == app.to_sis really asking "do these two throwaway instances share the same base API?" — through a string proxy. That's brittle: it's an identity check dressed up as a string compare, and two distinct APIs that happen to share a name (sameto_s) falsely dedup.Fix
Compare the base API by identity — the real signal the string proxy stands in for.
@basewas writer-only (base=), so this exposes a reader and compares it:Plain Rack apps have no base and are mounted as-is (same object across mounts), so they fall back to object identity.
Tests
refresh_already_mountedspecs still pass (same API → same base → deduped; no flag → duplicated).#to_scollision between two distinct APIs and asserts the refresh keys off base identity, not the string — it fails on the oldto_scompare (removes the wrong endpoint) and passes with this change.🤖 Generated with Claude Code