An invocation is a request to execute a handler. The Restate SDK client library lets you invoke Restate handlers from anywhere in your application. Use this only in non-Restate services without access to the Restate Context.
Each invocation has its own unique ID and lifecycle. Have a look at managing invocations to learn how to manage the lifecycle of an invocation.
Always invoke handlers via the context, if you have access to it. Restate then attaches information about the invocation to the parent invocation.

Invoking handlers with the SDK clients

First, add the dependency to your project
npm install @restatedev/restate-sdk-clients
Then, register the service you want to invoke. Finally, connect to Restate and invoke the handler with your preferred semantics.
  • Request-response invocations allow you to wait on a response from the handler.
// import * as clients from "@restatedev/restate-sdk-clients";
const restateClient = clients.connect({ url: "http://localhost:8080" });

// To call a service
const greet = await restateClient
  .serviceClient<MyService>({ name: "MyService" })
  .greet({ greeting: "Hi" });

// To call an object
const count = await restateClient
  .objectClient<MyObject>({ name: "MyObject" }, "Mary")
  .greet({ greeting: "Hi" });

// To call a workflow
const handle = await restateClient
  .workflowClient<MyWorkflow>({ name: "MyWorkflow" }, "someone")
  .workflowSubmit({ greeting: "Hi" });
const result = await restateClient.result(handle);

const status = await restateClient
  .workflowClient<MyWorkflow>({ name: "MyWorkflow" }, "someone")
  .myOtherHandler();
  • One-way invocations allow you to send a message without waiting for a response.
// import * as clients from "@restatedev/restateClient-sdk-clients";
const restateClient = clients.connect({ url: "http://localhost:8080" });

// To send a message to a service
await restateClient
  .serviceSendClient<MyService>({ name: "MyService" })
  .greet({ greeting: "Hi" });

// To send a message to an object
await restateClient
  .objectSendClient<MyObject>({ name: "MyObject" }, "Mary")
  .greet({ greeting: "Hi" });

// To send a message to a workflow
const handle = await restateClient
  .workflowClient<MyWorkflow>({ name: "MyWorkflow" }, "someone")
  .workflowSubmit({ greeting: "Hi" });
// You cannot send a message to a shared handler in a workflow
  • Delayed invocations allow you to schedule an invocation for a later point in time.
// import * as clients from "@restatedev/restate-sdk-clients";
const restateClient = clients.connect({ url: "http://localhost:8080" });

// To send a delayed message to a service
await restateClient
  .serviceSendClient<MyService>({ name: "MyService" })
  .greet({ greeting: "Hi" }, clients.rpc.sendOpts({ delay: { seconds: 1 } }));

// To send a delayed message to an object
await restateClient
  .objectSendClient<MyObject>({ name: "MyObject" }, "Mary")
  .greet({ greeting: "Hi" }, clients.rpc.sendOpts({ delay: { seconds: 1 } }));

// To send a delayed message to a workflow
const handle = await restateClient
  .workflowClient<MyWorkflow>({ name: "MyWorkflow" }, "someone")
  .workflowSubmit(
    { greeting: "Hi" },
    clients.rpc.sendOpts({ delay: { seconds: 1 } })
  );
// You cannot send a delayed message to a shared handler in a workflow

Invoke a handler idempotently

By using Restate and an idempotency key, you can make any service call idempotent, without any extra code or setup. This is a very powerful feature to ensure that your system stays consistent and doesn’t perform the same operation multiple times. To make a service call idempotent, you can use the idempotency key feature. Add the idempotency key to the header via:
await restateClient
  .serviceSendClient<MyService>({ name: "MyService" })
  .greet(request, clients.rpc.sendOpts({ idempotencyKey: "abcde" }));
After the invocation completes, Restate persists the response for a retention period of one day (24 hours). If you re-invoke the service with the same idempotency key within 24 hours, Restate sends back the same response and doesn’t re-execute the request to the service. The call options, with which we set the idempotency key, also let you add other headers to the request.
Check out the service configuration docs to tune the retention time.

Retrieve result of invocations and workflows

You can use the client library to retrieve the results of invocations with an idempotency key or workflows.

Attach to an invocation with an idempotency key

For invocations with an idempotency key, you can attach to the invocation and wait for it to finish:
// import * as clients from "@restatedev/restate-sdk-clients";
const restateClient = clients.connect({ url: "http://localhost:8080" });
// To send a message
const handle = await restateClient
  .serviceSendClient<MyService>({ name: "MyService" })
  .greet(request, clients.rpc.sendOpts({ idempotencyKey: "abcde" }));

// ... do something else ...

// Attach later to retrieve the result
const response = await restateClient.result(handle);

Attach/peek at a workflow execution

For workflows, you can attach to the workflow execution and wait for it to finish or peek at the output:
// import * as clients from "@restatedev/restate-sdk-clients";
const restateClient = clients.connect({ url: "http://localhost:8080" });

// Option 1: attach and wait for result with workflow ID
const result = await restateClient
  .workflowClient<MyWorkflow>({ name: "MyWorkflow" }, "someone")
  .workflowAttach();

// Option 2: peek to check if ready with workflow ID
const peekOutput = await restateClient
  .workflowClient<MyWorkflow>({ name: "MyWorkflow" }, "someone")
  .workflowOutput();
if (peekOutput.ready) {
  const result2 = peekOutput.result;
}

Advanced: sharing service type definitions

Have a look at the options listed in the Service Communication docs. These are also valid for the SDK clients.