fix(getTraits): stop camelizing collection-authored trait keys - #1989
Closed
crazywriter1 wants to merge 1 commit into
Closed
fix(getTraits): stop camelizing collection-authored trait keys#1989crazywriter1 wants to merge 1 commit into
crazywriter1 wants to merge 1 commit into
Conversation
getTraits returns objects keyed by trait names and trait values, but Fetcher camelizes every response body, so a collection with a fur_color trait is reported as furColor and a dark_brown value as darkBrown. Two values differing only in casing collapse into one entry with the wrong count. This is a v11 regression: getTraits landed in v10 (ProjectOpenSea#1787), and the blanket camelizeKeysDeep in api.ts arrived in v11.0.0 (e7deba3), replacing per-endpoint conversion in utils/converters.ts. The blanket pass assumes response keys are field names, which holds everywhere except this endpoint. Adds RequestOptions.camelizeResponse, mirroring the existing snakeizeBody opt-out, and sets it to false for getTraits. The response's own field names (categories, counts) are single words, so nothing is left unconverted.
Collaborator
|
Thanks for this! We recreated the fix in our internal monorepo, with you credited as co-author on the commit: This repo is a read-only mirror, so we can't merge PRs here directly, but we read every one. This will ship in the next |
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.
getTraitsreturns objects keyed by trait names and trait values, butFetchercamelizes every response body. A collection with afur_colortrait gets reported asfurColor, and itsdark_brownvalue asdarkBrown.Given this response:
{ "categories": { "fur_color": "string" }, "counts": { "fur_color": { "dark_brown": 12, "darkBrown": 3 } } }the SDK currently returns
counts.furColoras{ "darkBrown": 3 }. The rename alone breaks any lookup by trait name, but the two distinct values also collide into a single key — one trait silently disappears and the surviving count is wrong. Nothing in the response tells the caller this happened.Why this is a v11 regression
Response camelization is applied to every endpoint by
e7deba3in 11.0.0:That assumption — response keys are field names, so rewriting them is safe — holds for every spec-derived response.
getTraitspredates the change and is the one endpoint it doesn't hold for: the OpenAPI spec has no schema for/api/v2/traits/{slug}, only an example, whose keys are the collection's own trait names (face,background,level). Because there was no generated type to migrate to,GetTraitsResponsestayed hand-written insrc/api/types.tsas a pair of index signatures — while the blanket camelizer was applied to it along with everything else.Before v11 there was no camelization in
src/api/api.tsat all; conversion was per-endpoint inutils/converters.ts, which this endpoint never opted into. So this looks like collateral damage of the migration rather than an intentional choice.Why the tests didn't catch it
Every existing
getTraitstest mocks the fetcher (mockGet.mockResolvedValue(...)), so the camelization step never runs in the suite. The fixtures also happen to use casing-free names likeBackgroundandGolden Brown. One of them is already affected in principle —"Special-Character_123"would come back as"Special-Character123"through the real pipeline — but the mock means it never gets there.The fix
Adds
camelizeResponsetoRequestOptions, mirroring the existingsnakeizeBodyopt-out for request bodies, and sets it tofalseforgetTraits:Both
getandrequesthonour it, so the option doesn't silently do nothing on writes. Opting out is complete for this endpoint rather than a partial workaround: the response's own field names (categories,counts, andmin/maxfor numeric traits) are single words with nothing to convert, so everything left is data that must survive verbatim.GetTraitsResponseis unaffected at the type level, sinceCamelize<T>passes index signatures through unchanged.Scope is one endpoint —
GetTraitsResponseis the only response type insrc/api/types.tskeyed by data rather than by field names.Tests
test/api/api.spec.tsthat stubsfetchand asserts both trait names and trait values survive, including the two values that otherwise collide.expected { furColor: 'string' } to deeply equal { fur_color: 'string' }.test/api/collections.spec.tsasserting the opt-out is passed, so a future refactor ofgetTraitscan't quietly drop it.npm run check-typesand Biome clean.