End-to-end typesafe APIs made easy
trpc-svelte-query
A tRPC wrapper around @tanstack/svelte-query.
# pnpm
pnpm add trpc-svelte-query @tanstack/svelte-query
# Yarn
yarn add trpc-svelte-query @tanstack/svelte-query
# npm
npm install trpc-svelte-query @tanstack/svelte-query
Set up tRPC in lib/trpc/index.ts
import { createTRPCSvelte, httpBatchLink } from 'trpc-svelte-query';
// Import the router type from your server file
import type { AppRouter } from '$lib/server/routes/_app';
export const trpc = createTRPCSvelte<AppRouter>({
links: [
httpBatchLink({
url: '/api/trpc',
}),
],
});
Set up @tanstack/svelte-query
's provider in your root layout.
<script lang="ts">
import { QueryClientProvider } from '@tanstack/svelte-query';
import { trpc } from '$lib/trpc/client';
</script>
<QueryClientProvider client={trpc.queryClient}>
<slot />
</QueryClientProvider>
Set up your API handler in routes/api/trpc/[...trpc]/+server.ts
import { createTRPCSvelteServer } from 'trpc-svelte-query/server';
import { appRouter } from '$lib/server/routes/_app';
const trpcServer = createTRPCSvelteServer({
endpoint: '/api/trpc',
router: appRouter,
});
export const GET = trpcServer.handler;
export const POST = trpcServer.handler;
Now in any component, you can query your API using the client you created.
<script lang="ts">
import { trpc } from '$lib/trpc/client';
const query = trpc.greeting.query({ name: 'tRPC' });
</script>
{#if $query.isSuccess}
<p>{$query.data.greeting}</p>
{:else if $query.isError}
<p>{$query.error.message}</p>
{:else}
<p>Loading...</p>
{/if}
Extract your trpcServer
instance into its own file (i.e. $lib/server/server
). You'll use this object to handle SSR.
import { createTRPCSvelteServer } from 'trpc-svelte-query/server';
import { appRouter } from '$lib/server/routes/_app';
export const trpcServer = createTRPCSvelteServer({
endpoint: '/api/trpc',
router: appRouter,
});
Use that instance in your api endpoint:
import { trpcServer } from '$lib/server/server';
export const GET = trpcServer.handler;
export const POST = trpcServer.handler;
Add a root +layout.server.ts
to pass SSR data from the server to the client.
import { trpcServer } from '$lib/server/server';
import type { LayoutServerLoad } from './$types';
export const load: LayoutServerLoad = async (event) => {
return {
trpc: trpcServer.hydrateToClient(event),
};
};
Update your root layout to hydrate that SSR data.
<script lang="ts">
import { trpc } from '$lib/trpc/client';
import { QueryClientProvider } from '@tanstack/svelte-query';
import type { LayoutData } from './$types';
export let data: LayoutData;
$: queryClient = trpc.hydrateFromServer(data.trpc);
</script>
<QueryClientProvider client={queryClient}>
<slot />
</QueryClientProvider>
Add a +page.server.ts
file to preload specific queries.
import { trpc } from '$lib/server/server';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async (event) => {
await trpcServer.greeting.ssr({ name: 'tRPC' }, event);
};