Skip to content

SWR

Grabkit returns [data, error, meta]; SWR fetchers should throw on failure so error and isValidating behave as expected. Use orThrow from the package in your fetcher.

api.ts
import grabkit, { orThrow } from 'grabkit';
export const grab = grabkit(import.meta.env.VITE_API_URL, {
casing: 'camelCase',
});
export { orThrow };

The key is any stable serialisable value; the fetcher receives that key (or parts of it).

import useSWR from 'swr';
import { grab, orThrow } from './api';
type User = { id: string; name: string };
function useUser(id: string | null) {
return useSWR(id ? ['user', id] : null, async ([, userId]) => {
const [data] = await orThrow(grab<User>(`GET /users/${userId}`));
return data;
});
}
function Profile({ id }: { id: string }) {
const { data, error, isLoading } = useUser(id);
if (isLoading) return <p>Loading…</p>;
if (error) return <p>{error.message}</p>;
return <p>{data.name}</p>;
}

Passing null as the key disables the request until id is set.

If every request goes through the same grab callable, you can centralise the fetcher:

swr.ts
import { SWRConfig } from 'swr';
import { grab, orThrow } from './api';
export function SWRProvider({ children }: { children: React.ReactNode }) {
return (
<SWRConfig
value={{
fetcher: async (endpoint: string) => {
const [data] = await orThrow(grab(endpoint));
return data;
},
revalidateOnFocus: false,
}}
>
{children}
</SWRConfig>
);
}
import useSWR from 'swr';
function useUser(id: string) {
return useSWR(id ? `GET /users/${id}` : null);
}

Use this when the key is the endpoint string. For richer keys (arrays, objects), keep a custom fetcher as in the first example.

import useSWRMutation from 'swr/mutation';
import { grab, orThrow } from './api';
async function createUser(
_key: string,
{ arg }: { arg: { type: 'users'; name: string } },
) {
const [data] = await orThrow(grab(`POST /users`, { body: arg }));
return data;
}
function useCreateUser() {
return useSWRMutation('users/create', createUser);
}
function SignUpForm() {
const { trigger, isMutating, error } = useCreateUser();
return (
<button
disabled={isMutating}
onClick={() => trigger({ type: 'users', name: 'Leo' })}
>
Create
</button>
);
}

After a successful mutation, call mutate from useSWR or useSWRConfig to refresh related keys.

export const grab = grabkit('https://api.github.com', { format: 'json' });

See Plain JSON.