CRUD Operations
Problem
Implement crud operations in a production-friendly way with @vielzeug/fetchit while keeping setup and cleanup explicit.
Runnable Example
The snippet below is copy-paste runnable in a TypeScript project with @vielzeug/fetchit installed.
ts
import { createApi, createMutation, createQuery } from '@vielzeug/fetchit';
const api = createApi({ baseUrl: 'https://api.example.com' });
const qc = createQuery({ staleTime: 5_000 });
// READ — cached
const users = await qc.query({
key: ['users'],
fn: ({ signal }) => api.get<User[]>('/users', { signal }),
});
// READ one
const user = await qc.query({
key: ['users', 1],
fn: ({ signal }) => api.get<User>('/users/{id}', { params: { id: 1 }, signal }),
});
// CREATE
const addUser = createMutation((data: NewUser) => api.post<User>('/users', { body: data }), {
onSuccess: (user) => {
qc.set(['users', user.id], user);
qc.invalidate(['users']);
},
});
await addUser.mutate({ name: 'Alice', email: 'alice@example.com' });
// UPDATE
const updateUser = createMutation(
({ id, ...patch }: { id: number } & Partial<User>) => api.put<User>('/users/{id}', { params: { id }, body: patch }),
{ onSuccess: (user) => qc.set(['users', user.id], user) },
);
await updateUser.mutate({ id: 1, name: 'Alice Smith' });
// DELETE
const deleteUser = createMutation((id: number) => api.delete(`/users/${id}`), {
onSuccess: (_, id) => qc.invalidate(['users']),
});
await deleteUser.mutate(1);Expected Output
- The example runs without type errors in a standard TypeScript setup.
- The main flow produces the behavior described in the recipe title.
Common Pitfalls
- Forgetting cleanup/dispose calls can leak listeners or stale state.
- Skipping explicit typing can hide integration issues until runtime.
- Not handling error branches makes examples harder to adapt safely.