FastAPI

Mount pyRPC on a FastAPI application using mount_fastapi.

The FastAPI adapter mounts pyRPC onto a FastAPI app. Every registered procedure becomes callable at POST /rpc. Queries map to useQuery and mutations to useMutation on the frontend, no extra config needed.

1. Install

uv add pyrpc-core[fastapi]
# or
pip install "pyrpc-core[fastapi]"

2. Write the server

main.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from pyrpc_core import rpc
from pyrpc_fastapi import mount_fastapi

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:3000"],  # your frontend origin
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

@rpc.query
def read_root():
    return {"Hello": "World"}

@rpc.query
def read_item(item_id: int, q: str = None):
    return {"item_id": item_id, "q": q}

@rpc.mutation
def create_item(name: str, description: str = None):
    return {"name": name, "description": description, "created": True}

mount_fastapi(app)

3. Start the dev server

From the directory containing main.py:

pyrpc dev

First run launches a short wizard - backend framework (FastAPI is preselected when detected) and entry point, then client root and frontend framework - and writes pyrpc.json. Every subsequent run reads that file, no prompts. To skip the wizard entirely:

# auto-detect everything
pyrpc dev --yes

# fully explicit: good for CI
pyrpc dev --yes --framework fastapi --module main --client ../client

pyrpc dev starts uvicorn with your module[:app] entry point, generates __pyrpc.ts at the client project root, and re-generates it on every .py save. If a server is already running on that port, it skips starting uvicorn and only runs the type watcher.

4. Connect the frontend

Install the adapter for your frontend framework:

# React
npm install @pyrpc/react @tanstack/react-query

# Next.js
npm install @pyrpc/next @tanstack/react-query

# Vue
npm install @pyrpc/vue @tanstack/vue-query

# Svelte
npm install @pyrpc/svelte @tanstack/svelte-query

Then create the typed client, the import from @pyrpc/types resolves to the generated __pyrpc.ts in your client project:

lib/pyrpc.ts
import { createReactClient, httpBatchLink } from "@pyrpc/react"
import type { Types } from "@pyrpc/types"

export const api = createReactClient<Types>({
  links: [
    httpBatchLink({
      url: "http://localhost:8000",
    }),
  ],
})

See the React, Next.js, Vue, or Svelte docs for complete setup per framework.

How it works

  • @rpc.query / @rpc.mutation register the function in a global procedure registry and tag it with a kind.
  • mount_fastapi(app) adds two routes:
    • POST /rpc: procedure dispatch
    • GET /rpc: schema introspection (used by pyrpc dev to generate types)
  • The kind tag (query vs mutation) flows through codegen into the generated __pyrpc.ts file, which is how the frontend adapter knows which TanStack hook to expose on each procedure.

CORS origins by frontend

FrontendDefault dev origin
React (CRA)http://localhost:3000
React (Vite)http://localhost:5173
Next.jshttp://localhost:3000
Vue (Vite)http://localhost:5173
Svelte (Vite)http://localhost:5173

Routers

For larger projects, organize procedures into separate routers:

from pyrpc_core import Router
from pyrpc_fastapi import mount_fastapi

users = Router()
items = Router()

@users.query
def get_user(user_id: int): ...

@items.mutation
def create_item(name: str): ...

# Merge into the default router before mounting
from pyrpc_core import default_router
default_router.include(users, prefix="users")
default_router.include(items, prefix="items")

mount_fastapi(app)

Full working examples

ExampleFrontendSource
FastAPI + ReactReact + TanStack Queryexamples/fastapi-react
FastAPI + Next.jsNext.js App Router + RSCexamples/fastapi-nextjs
FastAPI + VueVue 3 + TanStack Vue Queryexamples/fastapi-vue
FastAPI + SvelteSvelte + TanStack Svelte Queryexamples/fastapi-svelte