Core
Response Format
Understanding the SpooshResponse structure
All Spoosh API calls return a consistent SpooshResponse object. This makes error handling predictable across your application.
Response Structure
type SpooshResponse<TData, TError> =
| { status: number; data: TData; error?: undefined; headers?: Headers; aborted?: false }
| { status: number; data?: undefined; error: TError; headers?: Headers; aborted?: boolean };Every response includes:
| Field | Type | Description |
|---|---|---|
status | number | HTTP status code |
data | TData | undefined | Response data (present on success) |
error | TError | undefined | Error object (present on failure) |
headers | Headers | undefined | Response headers |
aborted | boolean | undefined | True if request was aborted |
Handling Responses
The hooks automatically parse the response and provide separate data and error fields:
function UserProfile() {
const { data, error, loading } = useRead((api) => api.users[1].$get());
if (loading) return <Spinner />;
if (error) return <Error message={error.message} />;
return <div>{data.name}</div>;
}Aborting Requests
All hooks return an abort function to cancel in-flight requests:
function SearchUsers() {
const { data, loading, abort } = useRead(
(api) => api.search.$get({ query: { q: searchTerm } }),
{ enabled: searchTerm.length > 0 }
);
return (
<div>
<input
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
/>
{loading && <button onClick={abort}>Cancel</button>}
{data?.map((user) => <UserCard key={user.id} user={user} />)}
</div>
);
}useWrite Abort
function CreatePost() {
const { trigger, loading, abort } = useWrite(
(api, data) => api.posts.$post({ body: data })
);
const handleSubmit = async () => {
await trigger({ title: "New Post", content: "..." });
};
return (
<div>
<button onClick={handleSubmit} disabled={loading}>Submit</button>
{loading && <button onClick={abort}>Cancel</button>}
</div>
);
}useInfiniteRead Abort
function PostFeed() {
const { data, loading, abort, fetchNext } = useInfiniteRead(
(api, { pageParam }) => api.posts.$get({ query: { cursor: pageParam } }),
{ getNextPageParam: (lastPage) => lastPage.nextCursor }
);
return (
<div>
{loading && <button onClick={abort}>Cancel Loading</button>}
{/* ... */}
</div>
);
}Input Echo
The response includes the input that was sent with the request:
const { data } = useRead((api) =>
api.users.$post({ body: { name: "John", email: "john@example.com" } })
);
// response.input?.body contains { name: "John", email: "john@example.com" }This is useful for optimistic updates and debugging.