Documentation Index
Fetch the complete documentation index at: https://ship.paralect.com/docs/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Ship uses TanStack Query v5 with an auto-generated typed API client.
The typed client is generated from API endpoints via codegen — no manual hook creation needed.
Import the client from services/api-client.service:
import { apiClient } from 'services/api-client.service';
Queries (GET)
import { useApiQuery } from 'hooks';
import { apiClient } from 'services/api-client.service';
// Simple query
const { data, isLoading } = useApiQuery(apiClient.projects.list);
// With parameters
const { data } = useApiQuery(apiClient.projects.list, { page: 1, perPage: 10 });
Mutations (POST/PUT/DELETE)
import { useApiMutation } from 'hooks';
const { mutate, isPending } = useApiMutation(apiClient.projects.create);
mutate({ name: 'New Project' }, { onError: (e) => handleApiError(e, setError) });
Dynamic Path Params
useApiMutation binds pathParams at hook level — they’re fixed for all mutate() calls. For dynamic IDs (e.g., deleting different items in a list), use endpoint.call() directly:
import queryClient from 'query-client';
// ✅ Dynamic pathParams — use .call()
const handleDelete = async (id: string) => {
await apiClient.projects.remove.call({}, { pathParams: { id } });
queryClient.invalidateQueries({ queryKey: [apiClient.projects.list.path] });
};
// ✅ Fixed pathParams — hook level is fine
const { mutate: update } = useApiMutation(apiClient.projects.update, {
pathParams: { id: projectId },
});
Query Invalidation
import queryClient from 'query-client';
queryClient.invalidateQueries({ queryKey: [apiClient.projects.list.path] });
queryClient.setQueryData([apiClient.account.get.path], updatedData);
Query keys = [endpoint.path, ...params]. The first element is always the endpoint path string.
Error Handling
handleApiError(e, setError) from utils:
- Maps server validation errors → react-hook-form field errors
- Shows global errors via Sonner toast