Skip to main content
Skip table of contents

Writing a Greeter Client in TypeScript

This page presents a step-by-step guide to writing the client-side of our TypeScript Greeter application.

This client creates a proxy to a remote object that implements the Greeter interface and invokes the greet operation on this object.

You can find the complete source code for this example in the ice-demos repository.

Compile Slice File with Slice Compiler

The first step when writing a TypeScript application with Ice is to compile the Slice definitions for this application with the Slice to JavaScript compiler (slice2js).

Here, we compile the Greeter.ice Slice file created earlier. We recommend including this compilation step directly in your project’s build process, as demonstrated in the TypeScript demo programs.

These demos use a simple npm script that runs both slice2js and the TypeScript compiler together.

The Slice compiler generates two files from Greeter.ice: a TypeScript declaration file, Greeter.d.ts, and a JavaScript module, Greeter.js. The declaration file provides the APIs that our client code will call, so generating it is an essential first step in the development process.

Client Implementation

The structure of our client is going to look like:

TYPESCRIPT
import { Ice } from "@zeroc/ice";
import { VisitorCenter } from "./Greeter.js";
import process from "node:process";

...

Before anything else, we need to import a few modules:

  • Ice is imported from the @zeroc/ice package and gives us access to the Ice runtime.

  • VisitorCenter is imported from the generated Greeter.js module, produced by the slice2js compiler.

  • process is imported from Node’s built-in process module and provides access to command-line arguments.

Then we get to the interesting part: the client logic. We can break this logic down into four pieces:

1. Create a Communicator

First, we create a Communicator with Ice.initialize:

CPP
await using communicator = Ice.initialize(process.argv);

The communicator is the main entry point into the Ice runtime. Its responsibilities include establishing connections to servers, caching these connections, and managing configuration properties. We also need a communicator to create a proxy (see next step).

Our client, like most Ice applications, creates a single communicator.

It is important to make sure that your communicator is properly destroyed when no longer needed. This ensures that network connections are gracefully closed, and other important clean-up occurs. The easiest way to do this is with an await using like we do here.

2. Create a Greeter Proxy

Next, we need a way to call on a remote Greeter object. In Ice, this is done with proxies. Proxies are local constructs that represent remote Ice objects and provide methods to call operations on those objects.

We create a Greeter proxy by constructing an instance of the GreeterPrx class generated by the Slice compiler:

CPP
const greeter = new VisitorCenter.GreeterPrx(
    communicator,
    "greeter:tcp -h hello.zeroc.com -p 4061");

The constructor accepts our communicator and a “stringified proxy” with the address of the remote Ice object. Here, our stringified proxy says that the target Ice object is named “greeter” and can be reached via tcp on hello.zeroc.com on port 4061.

The name of the interface (Greeter) and the identity of the Ice object (greeter) are independent. The Ice objects hosted in the server could just as easily have identities like santa, bugsBunny, etc.

3. Make an Invocation

The third step is to call greet on the remote Ice object using our proxy and to print the greeting:

C#
const username = ...
const greeting = await greeter.greet(username);
console.log(greeting);

The greet method does all the heavy lifting for us: the proxy creates a request with the username string, the communicator establishes a connection to hello.zeroc.com:4061, and the request is sent over it. When a response is received, the proxy will unmarshal its payload and finally return a string (the greeting).

Note that greet returns a Promise that we await. This allows the JavaScript event loop to continue running other tasks while the invocation completes.

4. Cleanup

Finally, at the end of our logic, our communicator goes out of scope and it is disposed automatically (because we used await using), and then our application exits.

Running the Client

After building the client (see the demo’s README for instructions), you can run it with:

BASH
node client.js

Ice for JavaScript has limited server side support.

Here, we connect to the Greeter server running on hello.zeroc.com. This Ice server is implemented in a language with full server-side support (C++, C#, Java, Python, or Swift).

JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.