Async Server Actions

Call Async Python functions directly from your browser. Caspian eliminates manual API endpoints, leveraging FastAPI's high-performance ASGI engine.

How it Works

RPCs (Remote Procedure Calls) bridge the gap between your backend logic and frontend UI. By decorating an async def function with @rpc, it becomes callable from JavaScript using pp.rpc().

Secure by Default

Automatic CSRF protection, Origin validation, and integrated Authentication checks via Starlette middleware.

Non-Blocking I/O

Native async/await support allows your server to handle thousands of concurrent requests efficiently.

Type Safe

Python handles the logic with Pydantic validation; PulsePoint handles the reactivity.

Defining Actions (Backend)

In your route's index.py, import the decorator and define your logic using async def.

src/app/todos/index.py
from casp.rpc import rpc
from casp.validate import Validate
from casp.prisma.db import prisma

# 1. Simple Async RPC
@rpc()
async def create_todo(title):
    # Validations are easy
    if Validate.with_rules(title, "required|min:3") is not True:
        raise ValueError("Title must be at least 3 chars")

    # Non-blocking database call
    new_todo = await prisma.todo.create(data={
        'title': title,
        'completed': False
    })
    return new_todo.to_dict()

# 2. Secured RPC (Auto 401/403)
@rpc(require_auth=True)
async def delete_todo(id, _current_user_id=None):
    await prisma.todo.delete(where={'id': id})
    return {"success": True}

Calling Actions (Frontend)

Use pp.rpc(name, data) inside your scripts. It returns a Promise that resolves to the Python return value.

src/app/todos/index.html
<form onsubmit="add(event)">
  <input name="title" required />
  <button>Add</button>
</form>
<script>
const [todos, setTodos] = pp.state([]);

async function add(e) {
  e.preventDefault();
  
  // 1. Collect Data
  const formData = new FormData(e.target);
  const data = Object.fromEntries(formData);

  // 2. Call Async Python Function
  const newTodo = await pp.rpc("create_todo", data);

  // 3. Update State
  setTodos([newTodo, ...todos]);
  e.target.reset();
}

Full Example: Todo List

Here is the complete implementation of a CRUD Todo list. Notice how the logic uses async/await for database operations.