Svelte
Svelte + TanStack Svelte Query adapter with @pyrpc/svelte.
@pyrpc/svelte gives you typed createQuery / createMutation stores for every pyRPC procedure. Works with SvelteKit and plain Svelte.
Installation
npm install @pyrpc/svelte @tanstack/svelte-queryProject structure
my-app/
src/
lib/
pyrpc.ts ← createSvelteClient, import everywhere
routes/
+layout.svelte ← QueryClientProvider wrapper
+page.svelte ← api.greet.createQuery() etc.1. Create the client
import { createSvelteClient, httpBatchLink } from "@pyrpc/svelte"
import type { Types } from "@pyrpc/types"
export const api = createSvelteClient<Types>({
links: [
httpBatchLink({
url: import.meta.env.VITE_API_URL ?? "http://localhost:8000",
}),
],
})2. Wrap the layout
Svelte uses TanStack Svelte Query's QueryClientProvider directly in the layout, the standard approach:
<script lang="ts">
import { QueryClient, QueryClientProvider } from "@tanstack/svelte-query"
const queryClient = new QueryClient()
</script>
<QueryClientProvider client={queryClient}>
<slot />
</QueryClientProvider>3. Call procedures in pages
<script lang="ts">
import { api } from "$lib/pyrpc"
let name = ""
// @rpc.query → createQuery (returns a store)
const greeting = api.greet.createQuery()
// pass reactive args as a getter function
const item = api.read_item.createQuery(
() => ({ item_id: 42, q: "test" })
)
// @rpc.mutation → createMutation (returns a store)
const createItem = api.create_item.createMutation()
function handleCreate() {
if (name.trim()) {
$createItem.mutate({ name, description: `Item: ${name}` })
name = ""
}
}
</script>
{#if $greeting.isPending}
<p>Loading…</p>
{:else}
<pre>{JSON.stringify($greeting.data)}</pre>
{/if}
<pre>{JSON.stringify($item.data)}</pre>
<input bind:value={name} placeholder="Item name" />
<button on:click={handleCreate} disabled={$createItem.isPending}>
{$createItem.isPending ? "Creating…" : "Create"}
</button>
{#if $createItem.isSuccess}
<pre>{JSON.stringify($createItem.data)}</pre>
{/if}Prefix the store with $ to subscribe to its value, this is standard Svelte store syntax.
Reactive args
When query args come from reactive state, use a getter function:
let itemId = 1
const item = api.get_item.createQuery(() => ({ id: itemId }))
// changing itemId triggers a refetch automaticallyTypeScript
All parameter and return types are inferred from Python:
api.greet.createQuery() // ✓
api.read_item.createQuery(() => ({
item_id: 42, q: "test"
})) // ✓
api.read_item.createQuery(() => ({
item_id: "oops" // ✗, type error
}))Client config
| Option | Type | Default | Description |
|---|---|---|---|
links | Link[] | required | Link pipeline; exactly one terminating link (httpLink or httpBatchLink) |
kinds | ProcedureKindMap | generated | Override generated procedure kinds |
Invalidating after a mutation
Queries are cached under the key [QUERY_KEY_PREFIX, procedure, input] (QUERY_KEY_PREFIX is exported from @pyrpc/svelte). To invalidate after a mutation, use the shared TanStack Query client:
<script lang="ts">
import { useQueryClient } from "@tanstack/svelte-query"
import { QUERY_KEY_PREFIX } from "@pyrpc/svelte"
import { api } from "$lib/pyrpc"
const queryClient = useQueryClient()
const createItem = api.create_item.createMutation()
function handleCreate() {
createItem.mutate(
{ name: "Item" },
{
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: [QUERY_KEY_PREFIX, "list_items"] })
},
}
)
}
</script>Vanilla escape hatch
Every procedure also stays callable as a plain promise via api.client, which is the underlying vanilla client:
const greeting = await api.client.greet({ name: "World" })Full working examples
| Server | Source |
|---|---|
| FastAPI | examples/fastapi-svelte |
| Flask | examples/flask-svelte |
| Django | examples/django-svelte |

pyRPC