Skip to content

Callables

A Callable is a kind of Roli type that routes client calls to backend objects via code generated proxy classes. You can define a new Callable by deriving a class from either Endpoint or Session. Which base type you choose depends on what kind of logic you intend for it to contain.

Singletons

Callables are globally available Internet-connected singleton shared objects. This means that any number of client applications can call the same shared object instances at the same time. Callables are what developers typically think of as stateful microservices.

Remote Execution Model

Callables are ideal for housing code that needs to be run on the backend such as:

  • Internal or proprietary business logic (game servers, user/account management, billing, etc..)
  • Business rules specifying how data is saved, deleted, etc.
  • Any logic that benefits from being co-located with the database (i.e. performance sensitive).

Properties

Callables may contain any number of TypeScript properties with any name. You can create new properties in any Callable method, not just the constructor, just like any other POJO.

Data Types

Most built-in JavaScript/TypeScript property types are supported including:

  • undefined
  • null
  • number
  • boolean
  • object
  • Map
  • Set
  • Array
  • Date
  • BigInt
  • types that extend Data
  • types that extend Endpoint
  • types that extend Session

Explicitly Deleted

Callables live in the backend database until you explicitly delete them. Callables cannot be deleted from client-side code.

Stateful

Callables retain the values of all their properties between calls. This makes them stateful.

// Service code
export class MyApiEndpoint extends Endpoint { //Sessions work the same
private _usernames: Set<string>;
//...
addUser(username: string): void {
if (this._usernames.has(username))
throw new Error("A user with that name already exists");
this._usernames.add(username);
}

When client A calls addUser('Scott') if the user doesn’t already exist it will be saved and the endpoint’s this._usernames is updated.
Later, when client B calls addUser('Scott') the user will already exist and client B will get an error.

Call Semantics

When a client calls a method on a Callable reference, the request is sent over the Internet to the Roli backend where the Callable’s instance is hosted. The method is called on the Callable instance and if there wasn’t an error, the Callable’s changed properties are saved to the database.

Versioned

Callables are transparently versioned. Each time they’re changed and saved to the database the version changes. This version is used to ensure clients and services only work on the latest version of the Callable.

Automatically Saved

Any property changes made inside a Callable method call are saved automatically if the underlying call succeeds.

Implicitly Transactional

Each remote Callable method call is executed inside a database transaction. This means either all code inside the method works or no changes are made. This allows clients to retry calls without fear of data corruption.

Transaction Success or Failure

When the Callable method code is done executing, the following questions are asked to determine whether or not the transaction was successful:

  1. Was there a system-level error?
  2. Was an unhandled JavaScript exception thrown from user code?
  3. Were there any unsaved changes to Data instances? (E.g. Changed user._firstName but didn’t call saveData(user))
  4. Were there any concurrent, conflicting modifications to any objects modified by this transaction?

If the answer to any of these questions is yes, the transaction is rolled back causing all Data and Callable modifications made as a result of this call to be undone. The client will receive an exception it can handle gracefully.

However, if the answer to all these questions is no, the transaction is committed, the Callable method call is successful, and the the Callable method’s return statement is returned to the client.

Reverting Callable Changes

Sometimes while inside a Callable method call you may want to revert all the changes made since the start of the transaction without throwing an exception. This can be useful if you want to handle a deterministic data condition silently, without concerning clients.

// Service code
import {Endpoint, revertObject} from 'roli-runtime'
export class MyEndpoint extends Endpoint { //Sessions work the same
fooMethod(): void {
this.fooValue = 1; // create property named fooValue and assign the value 1
this.barValue = true; // create property named barValue and assign the value true
revertObject(this); // undoes those two property creations
}
}

Deletion

Callables can be deleted from inside service code using the deleteObject function.

// Service code
import {Endpoint, deleteObject} from 'roli-runtime'
export class MyEndpoint extends Endpoint { //Sessions work the same
deleteMe(): void {
deleteObject(this);
}
}

The deleteObject function leaves behind a flag in the database to prevent another object with the same type and key from being created. This design prevents accidental recreation. If you do not want this, pass true as the second argument to deleteObject.