@skmtc/gen-tanstack-query-fetch-zod
Produce Tanstack Query hooks (useQuery, useMutation) with fetch as the transport and Zod for runtime validation.
An operation generator. Composes with @skmtc/gen-zod for typed
request/response validation. The most-cloned client generator —
because the fetch wrapper, error handling, and base URL conventions
are almost always team-specific.
Source
skmtc-generators/gen-tanstack-query-fetch-zod/src/
What it generates
Per operation:
export const useGetUser = (args: { id: string }) =>
useQuery({
queryKey: ['getUser', args],
queryFn: () => fetch(`/users/${args.id}`).then(r => r.json()).then(user.parse)
})
export const useCreateUser = () =>
useMutation({
mutationFn: (body: User) =>
fetch('/users', { method: 'POST', body: JSON.stringify(userBody.parse(body)) })
.then(r => r.json()).then(user.parse)
})The user/userBody Zod schemas come from gen-zod via
insertNormalizedModel — both generators share a single registered
schema.
Key decisions
isSupportedfilter. GETs and DELETEs are always supported. POST/PUT/PATCH are supported only if the operation has a request body — operations without a body produce unhelpfully-typed mutations.- GET →
useQuery, mutation methods →useMutation. The mapping is hardcoded in the Projection. DELETE goes touseMutationdespite typically having no body. - Hardcoded
fetchtransport. No transport abstraction — the generated code callsfetchdirectly. This is the canonical customization seam: clone and replace with your own wrapper (axios, customapiFetch, etc.). - Hardcoded request validation. Request bodies are validated
with
<schema>.parse(body)before send. Errors throw at call time, not at hook setup.
What to learn from it
isSupportedfor operation filtering. The body-required check (Boolean(operation.toRequestBody(...))) shows how to gate generation on operation shape, not just method.- Composing with model generators. The hooks reference Zod schemas the form generator also references — the engine produces each schema once, with both generators contributing imports. This is the cross-generator coordination story in practice.
- Per-method dispatch in the Projection. GET → query,
POST/PUT/PATCH → mutation. The dispatch logic lives in the
Projection's
toString().
Common customizations when cloned
- Swap
fetchfor a custom wrapper. The most common edit. Your team'sapiFetchlikely handles auth, retries, and base URL — replace the literalfetch(...)calls. - Customize base URL handling. The stock produces relative paths; most teams want a base-URL prefix (env-driven, or threaded through deps).
- Add error handling. The stock throws raw fetch errors. Add retry policies, error boundaries, or transformation to a custom error class.
- Add
staleTime/gcTimedefaults. Per-query overrides via enrichments, or global defaults baked into the generator.
See also
- gen-zod — the schema generator this composes with
- gen-tanstack-query-supabase-zod — same shape, Supabase transport
- API: GenerateContext — insertNormalizedModel — how composition works
- Cross-generator coordination concept