Using clients
We have already been using the function createClient
in the tutorial. The
function gives us a client that uses ECMAScript promise objects. In combination
with the await
keyword, this lets you write asynchronous
code in a natural and easily readable way:
import { createClient } from "@connectrpc/connect";
import { ElizaService } from "@buf/connectrpc_eliza.bufbuild_es/connectrpc/eliza/v1/eliza_pb";
const client = createClient(ElizaService, transport);
const res = await client.say({
sentence: "I feel happy.",
});
console.log(res.sentence);
For server-streaming RPCs, the corresponding method on the client will return
an async iterable stream of response messages that can be used with the
for await...of
statement:
for await (const res of client.introduce({ name: "Joseph" })) {
console.log(res);
}
Callbacks
If you prefer a callback-based approach, the client returned by the function
createCallbackClient
should suit you:
import { createCallbackClient } from "@connectrpc/connect";
import { ElizaService } from "@buf/connectrpc_eliza.bufbuild_es/connectrpc/eliza/v1/eliza_pb";
const client = createCallbackClient(ElizaService, transport);
client.say({ sentence: "I feel happy." }, (err, res) => {
if (!err) {
console.log(res.sentence);
}
});
For server-streaming RPCs, the corresponding method on the client takes two callback functions: one that is called every time a response message arrives, and one that is called at the end of the stream.
import {ConnectError} from "@connectrpc/connect";
client.introduce({name: "Joseph"}, (res) => {
console.log(res);
}, (err?: ConnectError) => {
if (err) {
console.error(err);
}
});
The callback client is particularly useful if you want to migrate an existing code base from gRPC-web to Connect clients.
Managing clients and transports
In practice, you will likely want to avoid creating a new transport every time you want to use a client. It really depends on the framework of your choice, but there usually is a simple solution to avoid repetition.
For example, you can easily create a custom hook in React:
// use-client.ts
import { useMemo } from "react";
import { ServiceType } from "@bufbuild/protobuf";
import { createConnectTransport } from "@connectrpc/connect-web";
import { createClient, PromiseClient } from "@connectrpc/connect";
// This transport is going to be used throughout the app
const transport = createConnectTransport({
baseUrl: "https://demo.connectrpc.com",
});
/**
* Get a promise client for the given service.
*/
export function useClient<T extends ServiceType>(service: T): PromiseClient<T> {
// We memoize the client, so that we only create one instance per service.
return useMemo(() => createClient(service, transport), [service]);
}
Usage:
await useClient(ElizaService).say({sentence: "I feel happy."});