PyxlePyxle/Docs

Runtime API Reference

The pyxle.runtime module provides decorators and error classes used in .pyxl files. These are automatically available in the Python section of every .pyxl file -- you do not need to import them (the compiler injects the import).

@server

Marks an async function as a page data loader.

@server
async def load_page(request):
    return {"key": "value"}

Behaviour:

  • Attaches __pyxle_loader__ = True to the function (no wrapping)
  • The function must be async (enforced at compile time)
  • Receives a Starlette `Request` object
  • Must return a JSON-serializable dict
  • Can return a (dict, int) tuple to set the HTTP status code
  • Only one @server function is allowed per .pyxl file

Request object properties:

Property Type Description
request.path_params dict URL path parameters from dynamic routes
request.query_params QueryParams URL query string parameters
request.headers Headers HTTP request headers
request.cookies dict Request cookies
request.url URL Full request URL
request.method str HTTP method
request.state State Mutable state for middleware to attach data

@action

Marks an async function as a server action callable from React components.

@action
async def create_item(request):
    body = await request.json()
    return {"id": 1, "name": body["name"]}

Behaviour:

  • Attaches __pyxle_action__ = True to the function (no wrapping)
  • The function must be async
  • Receives a Starlette Request object
  • Must return a JSON-serializable dict
  • Multiple @action functions are allowed per .pyxl file
  • Accessible via POST /api/__actions/{page_path}/{action_name}
  • Protected by CSRF middleware by default

Client response format:

// Success
{ "ok": true, "id": 1, "name": "Item" }

// Error (from ActionError)
{ "ok": false, "error": "Error message" }

LoaderError

Exception class for structured loader errors. Triggers the nearest error.pyxl boundary.

from pyxle.runtime import LoaderError

@server
async def load_page(request):
    raise LoaderError("Not found", status_code=404, data={"id": 42})

Constructor:

LoaderError(message: str, status_code: int = 500, data: dict | None = None)
Parameter Type Default Description
message str (required) Error message displayed in the error boundary
status_code int 500 HTTP response status code
data dict | None None Additional JSON-serializable context

Properties:

Property Type Description
.message str The error message
.status_code int HTTP status code
.data dict Additional context (empty dict if None was passed)

ActionError

Exception class for structured action errors. Returns a JSON error response to the client.

@action
async def update_item(request):
    raise ActionError("Validation failed", status_code=400, data={"field": "name"})

Auto-imported since 0.3.0. Any .pyxl file that declares at least one @action gets from pyxle.runtime import ActionError injected by the compiler, so raise ActionError(...) works without you remembering to import it. A user-defined ActionError class (or an existing import) is respected and takes precedence.

Constructor:

ActionError(message: str, status_code: int = 400, data: dict | None = None)
Parameter Type Default Description
message str (required) Error message sent to the client
status_code int 400 HTTP response status code
data dict | None None Additional JSON-serializable payload

Properties:

Property Type Description
.message str The error message
.status_code int HTTP status code
.data dict Additional data (empty dict if None was passed)

invalidate_routes(response, *urls)

Tell the client router to evict its cached navigation payloads for urls before the caller's next navigation. Used by @action handlers that mutate data the client has already cached elsewhere.

from pyxle.runtime import invalidate_routes

@action
async def delete_post(request):
    ...
    # Drop the client's cached /posts so its next navigate() refetches.
    return invalidate_routes({"ok": True}, "/posts", "/dashboard")

The helper accepts either a plain dict (the usual @action return shape) or a Starlette Response / JSONResponse. In both cases Pyxle attaches an x-pyxle-invalidate: /posts, /dashboard header to the outgoing response. useAction and <Form> read this header automatically and call the client-side `invalidate(url)` for each listed URL — so mutation-driven cache invalidation works end-to-end with no extra wiring on the caller.

Parameters:

Parameter Type Description
response dict | Response The action's return value. Modified in place and returned.
*urls str URLs to invalidate. Empty / duplicate values are filtered.

Returns the response argument (possibly with a header or sentinel key added) so you can return invalidate_routes(...) in one line.

Document <head> elements

Pyxle offers two ways to contribute elements to the document <head>: the <Head> component (recommended) and the HEAD Python variable (lower-level alternative). Both are merged with automatic deduplication.

Imported from pyxle/client, usable anywhere in your JSX tree:

import { Head } from 'pyxle/client';

export default function Page({ data }) {
  return (
    <>
      <Head>
        <title>{data.title}</title>
        <meta name="description" content={data.description} />
        <link rel="canonical" href={data.canonicalUrl} />
      </Head>
      {/* ... */}
    </>
  );
}

See Head Management for the full pattern (layouts, deduplication, reusable SEO components, etc.).

HEAD variable (lower-level alternative)

Not part of pyxle.runtime but available in every .pyxl file. The HEAD variable is extracted at compile time by the parser; use it for fully-static head metadata that doesn't need React context, or for pages without a JSX component.

Static form:

# String
HEAD = '<title>Page Title</title>'

# List of strings
HEAD = ['<title>Page Title</title>', '<meta name="description" content="..." />']

Dynamic form (callable):

def HEAD(data):
    return f'<title>{data["title"]}</title>'

The callable receives the loader's return value. Must return a string or list of strings synchronously. For most dynamic head content, the <Head> component with normal JSX interpolation is simpler and more flexible.

Explicit imports

While the compiler auto-injects @server and @action, you can also import explicitly:

from pyxle.runtime import server, action, LoaderError, ActionError

This is useful for type checking and IDE support.