Backend services are a simple way to implement an internal service and an easy way to call JavaScript from HareScript code and vice versa. A backend service exposes the methods of an object over WebHare's RPC. Backend services cannot be reached from outside WebHare.

To define a backend service, expose a (possible async) callback to return the object:

  <services>
    <backendservice name="myservice" clientfactory="js/theservice.ts#getAMyServiceInstance" />
  </services>

And to connect to the service:

import * as services from "@webhare/services";

const service = await services.openBackendService("mymodule:myservice", args);

The methods inside the object are exported as wrappers which will invoke that call on the actual object. All method calls are treated as async (even if not explicitly declared so).

You can pass a {linger: true} option to openBackendService to have it keep its connection open until the service is explicitly closed.

The constructor, close and any method whose name starts with an underscore are not exported.

HareScript applications can connect to JS backend services using OpenWebHareService

TypeScript validation

TypeScript can help validate both the client and service side of a backend service. You can setup an interface both client and service should implement (the interface should be in a separate library or the client should import it using import type)

// The interface (should be exported from a common library or using import type)
export interface MyService {
  invokeAnyFunction(func: string, args: unknown[], options: InvokeOptions): Promise<unknown>;
  getText(): Promise<string>;
  getVersion(): Promise<number>;
}

//The server
async function getAMyServiceInstance() : Promise<MyService> {
}

//The client
await services.openBackendService<MyService>("mymodule:myservice");

Controllers

A service can set up controller which will be invoked immediately and will be used to create the actual clients. A controller allows you to more easily share state between clients and to have the service run independently of any connections. Setting up a controller disabled on-demand startup for the service

A controller should implement the BackendServiceController interface and provide a createClient member to create new clients.

To setup a controller, replace the clientfactory= with a controllerfactory=:

  <services>
    <backendservice name="myservice" controllerfactory="js/theservice.ts#gcreateController" />
  </services>