Skip to main content

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. Includes title, description, id, owner_id, and created_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:

  1. The onSettled or onSuccess callback in your mutation calls queryClient.invalidateQueries({ queryKey: ["items"] }).
  2. The queryKey used in useQuery exactly matches the one used in invalidateQueries.
  3. You are handling ApiError using the project's handleError utility to see validation errors from the backend.