Skip to content

chore(admin): generate typesafe API client + adopt TanStack Query #7638

@JohnMcLear

Description

@JohnMcLear

Spun out of #7601 review feedback from @SamTV12345.

Problem

The admin UI currently hand-writes fetch calls in useEffect throughout (UpdateBanner, UpdatePage, plus the existing settings/plugins/users pages). Two issues with this:

  1. Pattern is officially discouraged — see the React docs: https://react.dev/reference/react/useEffect#fetching-data-with-effects (no caching, no dedup, no race-condition handling, manual loading states).
  2. Endpoint shape is duplicated — every fetch site re-types the request and response by hand. We already publish a Swagger/OpenAPI spec that describes these endpoints authoritatively, so any drift between the spec and the hand-written types is a silent bug.

Proposal

Generate the admin's API client directly from the OpenAPI spec, and use TanStack Query as the runtime.

Toolchain:

  • openapi-typescript — generates a TS types file from src/node/hooks/express/swagger.ts output. Run as a build step; the result is checked in or generated pre-build.
  • openapi-fetch — typed fetch wrapper that consumes the generated types. Zero runtime overhead, ~3 KB gzipped.
  • openapi-react-query — thin TanStack Query bindings that derive query/mutation hooks from the same generated types. Caching, dedup, refetch-on-focus, devtools all come along for free.
  • @tanstack/react-query — the runtime.

Net result: every endpoint becomes one line — useQuery({ ...client.GET("/admin/...") }) — with full request/response inference and no hand-written types.

Scope

  • Wire the OpenAPI generator into the admin build pipeline (or the root pnpm build).
  • Add @tanstack/react-query + provider at the admin root, plus React Query Devtools in dev.
  • Migrate every useEffect+fetch site in admin/src/ to the generated hooks.
  • Replace if (!data) return null patterns with Suspense boundaries (useSuspenseQuery).
  • Document the codegen step in admin/README so contributors know how to regen after API changes.

Out of scope

  • Migrating the pad-side frontend (different bundle, different concerns).
  • Backend changes — the OpenAPI spec is the contract; if anything moves, that moves first.

Why now

Tracking out of #7601 specifically — that PR adds two new admin fetch sites, and bundling this migration into it would balloon the diff. Cleaner as a dedicated PR.

Metadata

Metadata

Assignees

No one assigned

    Labels

    AdminNeeds rewriteNeeds rewrite as it was improperly implemented.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions