Fitz Introduces RPC for Seamless Server-WASM Interaction

Fitz, a framework for building full-stack applications with WebAssembly, has introduced a novel Remote Procedure Call (RPC) mechanism that fundamentally simplifies how developers interact with server-side logic from their client-side WASM components. This new feature, detailed in the latest installment of the FitzLiveViews series, allows developers to invoke server functions as if they were local, effectively removing the need for manual API endpoint creation, fetch requests, and data serialization glue code.

The core of this innovation lies in a simple annotation: marking an async fn with @rpc. Once declared, this function becomes callable directly from a .fitzv component. For instance, a call like let u = get_user(42).await? transparently handles the communication with the server. The Fitz compiler intelligently generates both halves of the communication: a server-side endpoint (e.g., POST /__rpc/get_user) capable of accessing databases, authentication systems, and secrets, and a client-side stub function that manages the network request.

This approach ensures that the shared type definitions between the client and server are maintained rigorously. The entire process bypasses the traditional web development plumbing: no manual HTTP handler setup, no explicit fetch calls, no JSON serialization or deserialization, no manually written routes, and crucially, no external dependencies for this core functionality. This marks a significant step towards the 'entire stack together, no plumbing' vision that Fitz aims to deliver.

The previous parts of the FitzLiveViews series established how a .fitzv component can compile into two distinct forms: server-rendered HTML via LiveViews over WebSockets, and a standalone Single-Page Application (SPA) compiled to WebAssembly. This new RPC feature bridges these two worlds more effectively, allowing a single function declaration to serve both server-side and client-side needs without duplication or manual synchronization.

How the RPC Mechanism Works

The magic behind Fitz's RPC lies in its compiler. When a developer defines an asynchronous function and annotates it with @rpc, the compiler performs a dual compilation process. On the server-side, it generates a route handler that listens for incoming requests. This handler is responsible for receiving the function arguments, executing the actual server-side logic of the annotated function, and returning the result. This logic can freely interact with server-specific resources like databases, file systems, or secret management systems, as it runs in the server environment.

On the client-side, specifically within the WebAssembly component, the compiler generates a proxy function. This proxy function has the exact same signature as the original server function. When invoked, it serializes the provided arguments, constructs an HTTP request (typically a POST request to a dedicated RPC endpoint on the server), sends it, waits for the response, deserializes the result, and returns it. The developer experience is that of a local function call, abstracting away all the network and serialization complexities.

Diagram showing Fitz RPC flow: Client WASM calls function, compiler generates fetch stub, server receives request, executes function, returns result.

The critical aspect here is the shared type system. Because both the client stub and the server handler are generated from the same source function definition, there is an inherent guarantee that the types of arguments and return values are perfectly aligned. This eliminates a common source of bugs in distributed systems: mismatches between client and server expectations regarding data structures.

Eliminating Boilerplate and External Dependencies

Traditional web development often involves significant boilerplate code for creating APIs. Developers typically need to define API routes, write request handlers, parse incoming data (often JSON), validate it, call business logic, serialize the results, and construct HTTP responses. On the client-side, they need to write corresponding fetch or axios calls, handle different response statuses, and deserialize the data. This process is repetitive, error-prone, and adds considerable overhead, especially for applications with many inter-component communications.

Fitz's RPC system directly addresses this pain point. By abstracting away the HTTP layer, serialization, and routing, it allows developers to focus purely on the business logic. The @rpc annotation and the subsequent direct function call are all that's needed. This not only speeds up development but also makes the codebase cleaner and easier to maintain. Furthermore, the fact that this functionality is built into the framework and its compiler means there's no need to add external libraries for RPC, REST clients, or API definition languages, reducing the project's dependency footprint.

Implications for Full-Stack Development

The introduction of this RPC feature significantly enhances Fitz's value proposition as a unified full-stack framework. It provides a cohesive way to build applications where components can seamlessly interact with server-side resources without the typical friction associated with distributed systems. This is particularly powerful for developers who are already leveraging Fitz for its LiveView capabilities or its standalone WASM compilation.

For developers accustomed to the intricacies of client-server communication, this abstraction is a welcome relief. It allows for a more direct and intuitive way of thinking about application architecture. Instead of thinking about network endpoints and data formats, they can think about functions and data flow. This mental model shift can lead to faster iteration cycles and more robust applications. The ability to define a function once and have it usable on both the server and client, with the compiler handling the bridge, represents a substantial gain in developer productivity.

The