refactor(utilities): unify list/detail serializer + ?fields= support (ALL-733)#208
Merged
texture-fleet-agent[bot] merged 1 commit intomainfrom May 6, 2026
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…(ALL-733)
Problem: The /utilities list endpoint and /utilities/{slug} detail endpoint
used different code paths for sparse-fieldset projection. The list route had
a local selectFields helper; the detail route had no sparse-fieldset support
at all. This meant:
- Detail endpoint couldn't honor ?fields= (returned the full shape).
- List endpoint's sparse projection wasn't reused anywhere else.
- No invariant that list and detail produce the same per-record shape
when given the same inputs.
Morgan caught the end-user impact in the Relay recon (2026-05-06, bug #2):
for a 3,133-utility sync at the Registered 5k/hr tier, having to fall back
to list-then-detail was ~38 min instead of ~2 sec.
Fix:
- Hoist selectFields + parseFieldsParam into lib/api/public-response.ts so
every public route uses the same serializer pipeline.
- Extend publicJsonResponse and publicPaginatedResponse with an optional
{ fields } option (accepts raw ?fields= string or pre-parsed string[]).
- Enforce order: stripInternal → selectFields. Internal fields can never be
resurrected via ?fields=searchVector etc.
- Wire ?fields= into /utilities/{slug}.
- Swap the ad-hoc selectFields in /utilities route.ts for the shared helpers.
Regression tests (lib/api/__tests__/public-response.test.ts):
- parseFieldsParam: null/empty/whitespace handling, de-duping w/ preserved
order.
- selectFields: existing-keys-only, null/0 preserved, non-object passthrough.
- publicJsonResponse + publicPaginatedResponse with ?fields=.
- Internal-field resurrection guard.
- List/detail shape parity: same keys, same numeric values, same ?fields=
projection across both envelopes.
Fixes ALL-733
4fd0353 to
5975206
Compare
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
Morgan's Relay recon (bug #2, 2026-05-06) flagged two related issues with
/utilities:?fields=on detail —/utilities/{slug}?fields=id,namereturned the full shape, so a client that opted into a sparse list couldn't pair it with a sparse detail.At the Registered 5k/hr tier that forced any sync of 3,133 utilities to ~38 min of list-then-detail calls instead of ~2 sec.
Fix
Hoist
parseFieldsParam+selectFieldsintolib/api/public-response.tsso every public route uses the same serializer pipeline, and extend both envelope builders to accept a{ fields }option:The option accepts either the raw
?fields=string or a pre-parsedstring[]. Order is enforced:stripInternal → selectFields, so internal fields (e.g.searchVector,submittedBy) can never be resurrected via?fields=searchVector.Wiring:
GET /api/v1/utilities/{slug}now reads?fields=and passes it throughpublicJsonResponse.GET /api/v1/utilitiesreplaced its ad-hoc localselectFieldswith the shared helpers.Tests
lib/api/__tests__/public-response.test.tsnow covers:parseFieldsParam— null/empty/whitespace handling, comma/whitespace splitting, de-duping with preserved order.selectFields— existing-keys-only,null/0values preserved (not confused with missing), non-object inputs passed through.publicJsonResponse+publicPaginatedResponsewith?fields=— happy path, pre-parsed array input, internal-field resurrection guard, omitted-param fallthrough.publicJsonResponse(row)andpublicPaginatedResponse([row])produce identical keys and values; numeric fields (customerCount,totalMeterCount,amiMeterCount,peakDemandMw) survive both envelopes;?fields=id,slug,name,customerCountyields identical projections on both.All 126 tests pass.
npm run buildis green.biome checkon touched files is clean.Fixes ALL-733.