Skip to content

Extract a fetchJson helper for throw-on-error fetches - #193

Merged
skearnes merged 2 commits into
mainfrom
cleanup/frontend-fetch-helper
Jun 21, 2026
Merged

Extract a fetchJson helper for throw-on-error fetches#193
skearnes merged 2 commits into
mainfrom
cleanup/frontend-fetch-helper

Conversation

@skearnes

@skearnes skearnes commented Jun 21, 2026

Copy link
Copy Markdown
Member

What

The Tier 2 frontend cleanup. The data-fetching hooks/components repeated the same boilerplate — await fetch, check response.ok, otherwise throw new Error(\ failed (HTTP )`), then parse JSON. This extracts it into fetchJson` in app/src/utils/api.ts and migrates the five sites that share those exact semantics:

  • ChartView.tsx: the compound_svg POST and the chart-data GET (the AbortController signal passes straight through — AbortError still rejects before the ok-check, so the existing .catch guard is unaffected).
  • MainDatasetView.tsx: the dataset-metadata react-query queryFn.
  • useSearchTask.ts: the submit_query call.
  • MainSelectedSet.tsx: the /reactions POST.

Deliberately left alone

The other fetch sites don't share these semantics, so forcing them through the helper would change behavior or hurt readability:

  • Error-swallowing sitesMainReactionView (×2), CompoundView, ReactionCard, ModalKetcher return null/'' (or console.warn) on a bad response on purpose, so an HTML error body never reaches dangerouslySetInnerHTML. Documented inline at each site.
  • Status-branchinguseSearchTask's poll dispatches on specific 200/202 codes.
  • No-opMainBrowse has no ok check today; out of scope.

Verification

  • npm run build (tsc typecheck + vite) passes.
  • npm run lint (ESLint) and npm run format:check (Prettier) clean.
  • No behavior change at the migrated sites (same throw-on-error → parse-JSON semantics; thrown message format preserved).

Follow-up

The other half of the Tier 2 frontend plan — the 4 unrendered-measurement TODOs in ConditionsView — are genuine feature gaps, so they're tracked in #192 rather than implemented here.

🤖 Generated with Claude Code

Greptile Summary

This PR extracts a reusable fetchJson<T> helper in app/src/utils/api.ts that centralizes the fetch-then-check-ok-then-parse-JSON pattern, and migrates five call sites that share exactly those semantics.

  • New fetchJson helper (api.ts): throws "${label} failed (HTTP ${status})" on non-2xx, accepts any RequestInit (including AbortSignal), and falls back gracefully when no label is supplied.
  • Five sites migrated (ChartView, MainDatasetView, useSearchTask, MainSelectedSet): each replaces 5–8 lines of inline boilerplate with a single fetchJson call; error-swallowing sites and the status-branching poll in useSearchTask are deliberately left untouched with inline explanations.

Confidence Score: 5/5

Pure refactor with no behavior change at the migrated sites; safe to merge.

All five migrations preserve the original throw-on-error → parse-JSON flow. The AbortController signal passes through fetchJson unchanged, keeping the chart-data fetch's abort guard intact. The dangerouslySetInnerHTML protection in ChartView (throw on non-2xx → catch sets molHtml to null) is explicitly preserved. The one minor wording shift in MainSelectedSet's error message is console-only and not user-visible. No logic was altered.

No files require special attention.

Important Files Changed

Filename Overview
app/src/utils/api.ts New fetchJson helper: correct generic signature, ok-check, and label-fallback logic. All current call sites supply an explicit label, so the fallback branch is unused but harmless.
app/src/views/dataset-view/ChartView.tsx Both fetch sites migrated to fetchJson; AbortController signal threads through correctly, and the dangerouslySetInnerHTML guard (throw on non-2xx → catch sets molHtml to null) is preserved.
app/src/hooks/useSearchTask.ts submit_query call migrated to fetchJson; the fetch_query_result poll is intentionally left as raw fetch since it dispatches on 200 vs 202.
app/src/views/browse/selected-set/MainSelectedSet.tsx reactions POST migrated to fetchJson. Error message wording changed from "Failed to fetch reactions" (no status code) to "reactions failed (HTTP )"; the error is only console-logged so there is no user-visible regression.
app/src/views/dataset-view/MainDatasetView.tsx dataset-metadata queryFn simplified to a direct fetchJson call; non-async arrow function returning a Promise is correct for react-query.

Reviews (2): Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." | Re-trigger Greptile

skearnes and others added 2 commits June 20, 2026 21:51
The data-fetching hooks/components repeated the same "await fetch, check
response.ok, otherwise throw `<label> failed (HTTP <status>)`, then parse
JSON" boilerplate. Extract it into `fetchJson<T>` in utils/api.ts and use
it at the five sites that share those exact semantics:

- ChartView: compound_svg POST and the chart-data GET (the AbortController
  signal is passed straight through; AbortError still propagates).
- MainDatasetView: dataset-metadata react-query queryFn.
- useSearchTask: the submit_query call.
- MainSelectedSet: the /reactions POST.

Sites that deliberately *swallow* errors are intentionally left alone:
MainReactionView, CompoundView, ReactionCard, and ModalKetcher return
null/'' (or warn) on a bad response so an HTML error body never reaches
dangerouslySetInnerHTML, and useSearchTask's poll branches on specific
200/202 status codes. Those don't fit a throw-on-error helper.

No behavior change at the migrated sites; `npm run build` (tsc + vite)
and `npm run lint` pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@skearnes
skearnes merged commit b7dc77f into main Jun 21, 2026
16 checks passed
@skearnes
skearnes deleted the cleanup/frontend-fetch-helper branch June 21, 2026 02:31
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.

1 participant