Build with Rivet

Remote Procedure Calls

Remote procedure calls (RPC) are how clients communicate with actors. RPCs are as simple as writing a method on the actor class and then calling it from the client.


Writing RPCs

RPCs can be written as native JavaScript methods on the actor class.

For example, the multiplyByTwo method is written as:

export class Example extends Actor {
  // This is an RPC
  multiplyByTwo(rpc: Rpc<this>, x: number) {
    return x * 2;
  }
}
TypeScript

Private methods

Methods starting with _ or # (e.g. _myMethod and #myMethod) are private and cannot be called by clients.

All Rivet-provided methods start with _ (e.g. _broadcast) so clients cannot call them.

For example:

export default class Example extends Actor {
  // This is private and cannot be called by clients
  #calcFibonacci(n: number): number {
    if (n <= 1) return n;
    return this.#calcFibonacci(n - 1) + this.#calcFibonacci(n - 2);
  }

  // This is public and can be called by clients
  fetchFibonacci(rpc: Rpc<this>, n: number): number {
    return this.#calcFibonacci(n);
  }
}
TypeScript

Streaming return data

RPCs have a single return value. In order to stream realtime data in response to an RPC, use events.


Calling RPCs

Calling RPCs is as simple as calling any other JavaScript function.

import type { Counter } from './counter.ts';

const actor = await client.get<Counter>({ name: 'counter' });
await actor.increment(42);
TypeScript

Type safety

The Rivet client includes type safety out of the box. The first generic parameter in get<Actor>(...) defines the actor class. You can safely import the actor's type with import type in to the client, like this:

import type { Counter } from './counter.ts';
// ...setup...
const actor = await client.get<Counter>(/* ... */);
await actor.increment(123); // passes
await actor.increment('non-number type'); // compile error
await actor.nonexistentMethod(123); // compile error

Schema validation

Data schemas are not validated by default. For production applications, use a library like zod to validate input types.

In the previous example, providing a non-number value to count could corrupt the actor's state (e.g. by passing a string instead of a number). For example, to validate the increment request schema:

import { z } from 'zod';

// Define schemas for user requests
const IncrementOptionsSchema = z.object({
  count: z.number().int()
});

type IncrementOptions = z.infer<typeof IncrementOptionsSchema>;

export class Counter extends Actor {
  increment(rpc: Rpc<this>, opts: IncrementOptions) {
    // Will throw error if input is invalid
    const validatedOpts = IncrementOptionsSchema.parse(opts);

    // ...etc...
  }
}
TypeScript

Authentication

By default, clients can call all RPCs on an actor without restriction. Make sure to implement authentication if needed. Documentation on authentication is available here.