← Back to Blog

Flask + React: lightweight Python, full type safety

·9 min read

Flask is the minimal Python web framework, no ORM, no admin, just routes. pyRPC's Flask adapter adds a single POST /rpc endpoint to your Flask app, and the React client stays completely identical to the FastAPI version. The only differences are the import paths and the default port (5000 vs 8000).

The server

# server/main.py
from flask import Flask
from flask_cors import CORS
from pyrpc_core import rpc
from pyrpc_flask import mount_flask

app = Flask(__name__)
CORS(app, origins=["http://localhost:3000"])

@rpc.query
def greet(name: str = "World") -> dict:
    return {"message": f"Hello, {name}!", "framework": "Flask"}

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

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

mount_flask(app)

if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=5000)

Note the port: Flask defaults to 5000, not 8000. Update baseUrl in your client accordingly.

Start the dev server

cd server
uv add pyrpc-core[flask]
pyrpc dev   # wizard → writes pyrpc.json, starts Flask on :5000

# or skip the wizard
pyrpc dev --yes --module main --client ../client

Client, identical pattern, different port

// src/pyrpc.ts
import { createReactClient } from "@pyrpc/react"
import type { Types } from "@pyrpc/types"

export const api = createReactClient<Types>({
  baseUrl: process.env.REACT_APP_API_URL ?? "http://localhost:5000",
})
// src/App.tsx
import { useState } from "react"
import { api } from "./pyrpc"

function App() {
  const [name, setName] = useState("")

  const { data: greeting, isLoading } = api.greet.useQuery({ name: "Flask User" })
  const { data: item } = api.read_item.useQuery({ item_id: 42, q: "test" })
  const createItem = api.create_item.useMutation()

  return (
    <api.Provider>
      {isLoading ? <p>Loading…</p> : <pre>{JSON.stringify(greeting)}</pre>}
      <pre>{JSON.stringify(item)}</pre>
      <input value={name} onChange={e => setName(e.target.value)} />
      <button onClick={() => createItem.mutate({ name })} disabled={createItem.isPending}>
        {createItem.isPending ? "Creating…" : "Create"}
      </button>
      {createItem.isSuccess && <pre>{JSON.stringify(createItem.data)}</pre>}
    </api.Provider>
  )
}

Run it

# Terminal 1
cd server && pyrpc dev

# Terminal 2
cd client && npm install && npm start

Open http://localhost:3000. Full source at examples/flask-react.