Resource Management
To manage application items and their ownership in this project, you use the ItemsService class in conjunction with TanStack Query for state management and cache synchronization.
Fetching Items with Pagination
To retrieve a list of items, use ItemsService.readItems within a useSuspenseQuery or useQuery hook. This ensures the UI stays in sync with the backend and handles loading states automatically.
// From frontend/src/routes/_layout/items.tsx
import { useSuspenseQuery } from "@tanstack/react-query"
import { ItemsService } from "@/client"
function getItemsQueryOptions() {
return {
queryFn: () => ItemsService.readItems({ skip: 0, limit: 100 }),
queryKey: ["items"],
}
}
function ItemsTableContent() {
// useSuspenseQuery handles the loading state via React Suspense
const { data: items } = useSuspenseQuery(getItemsQueryOptions())
// items.data contains the array of ItemPublic objects
return <DataTable columns={columns} data={items.data} />
}
Creating a New Item
To create an item, use useMutation to call ItemsService.createItem. You must invalidate the ["items"] query key on success to refresh the list.
// Based on frontend/src/components/Items/AddItem.tsx
import { useMutation, useQueryClient } from "@tanstack/react-query"
import { ItemsService, type ItemCreate } from "@/client"
import { handleError } from "@/utils"
const queryClient = useQueryClient()
const mutation = useMutation({
mutationFn: (data: ItemCreate) =>
ItemsService.createItem({ requestBody: data }),
onSuccess: () => {
showSuccessToast("Item created successfully")
reset() // Reset form
onClose() // Close modal
},
onError: (err: ApiError) => {
handleError(err, showErrorToast)
},
onSettled: () => {
// Refresh the items list
queryClient.invalidateQueries({ queryKey: ["items"] })
},
})
// Trigger the mutation
// mutation.mutate({ title: "New Item", description: "Details" })
Updating an Existing Item
Updating an item requires the item's ID and an ItemUpdate payload. Use ItemsService.updateItem within a mutation.
// Based on frontend/src/components/Items/EditItem.tsx
import { ItemsService, type ItemUpdate, type ItemPublic } from "@/client"
const mutation = useMutation({
mutationFn: (data: ItemUpdate) =>
ItemsService.updateItem({ id: item.id, requestBody: data }),
onSuccess: () => {
showSuccessToast("Item updated successfully")
onClose()
},
onError: (err: ApiError) => {
handleError(err, showErrorToast)
},
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ["items"] })
},
})
Deleting an Item
To delete an item, call ItemsService.deleteItem with the specific item ID.
// From frontend/src/components/Items/DeleteItem.tsx
import { ItemsService } from "@/client"
const deleteItem = async (id: string) => {
await ItemsService.deleteItem({ id: id })
}
const mutation = useMutation({
mutationFn: deleteItem,
onSuccess: () => {
showSuccessToast("The item was deleted successfully")
},
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ["items"] })
},
})
Key Data Structures
The ItemsService uses generated TypeScript interfaces to ensure type safety:
ItemPublic: The structure returned by the API. Includestitle,description,id,owner_id, andcreated_at.ItemCreate: Required fields for creation (e.g.,title).ItemUpdate: Optional fields for updates (e.g.,title,description).
Troubleshooting Cache Invalidation
If the UI does not update after a create, update, or delete operation, ensure that:
- The
onSettledoronSuccesscallback in your mutation callsqueryClient.invalidateQueries({ queryKey: ["items"] }). - The
queryKeyused inuseQueryexactly matches the one used ininvalidateQueries. - You are handling
ApiErrorusing the project'shandleErrorutility to see validation errors from the backend.