Server
Introduction
The Dapr Server will allow you to receive communication from the Dapr Sidecar and get access to its server facing features such as: Subscribing to Events, Receiving Input Bindings, and much more.
With JavaScript SDK 3.19.0 or later, register scheduled job callbacks through server.jobs.listen(name, callback). See the Jobs how-to guide for a runnable example and the callback usage guidance for acknowledgments, retries, and protocol requirements.
Pre-requisites
- Dapr CLI installed
- Initialized Dapr environment
- Latest LTS version of Node or greater
Installing and importing Dapr’s JS SDK
- Install the SDK with
npm:
npm i @dapr/dapr --save
- Import the libraries:
import { DaprServer, CommunicationProtocolEnum } from "@dapr/dapr";
const daprHost = "127.0.0.1"; // Dapr Sidecar Host
const daprPort = "3500"; // Dapr Sidecar Port of this Example Server
const serverHost = "127.0.0.1"; // App Host of this Example Server
const serverPort = "50051"; // App Port of this Example Server
// HTTP Example
const server = new DaprServer({
serverHost,
serverPort,
communicationProtocol: CommunicationProtocolEnum.HTTP, // DaprClient to use same communication protocol as DaprServer, in case DaprClient protocol not mentioned explicitly
clientOptions: {
daprHost,
daprPort,
},
});
// GRPC Example
const server = new DaprServer({
serverHost,
serverPort,
communicationProtocol: CommunicationProtocolEnum.GRPC,
clientOptions: {
daprHost,
daprPort,
},
});
Running
To run the examples, you can use two different protocols to interact with the Dapr sidecar: HTTP (default) or gRPC.
Using HTTP (built-in express webserver)
import { DaprServer } from "@dapr/dapr";
const server = new DaprServer({
serverHost: appHost,
serverPort: appPort,
clientOptions: {
daprHost,
daprPort,
},
});
// initialize subscribtions, ... before server start
// the dapr sidecar relies on these
await server.start();
# Using dapr run
dapr run --app-id example-sdk --app-port 50051 --app-protocol http -- npm run start
# or, using npm script
npm run start:dapr-http
ℹ️ Note: The
app-portis required here, as this is where our server will need to bind to. Dapr will check for the application to bind to this port, before finishing start-up.
Using HTTP (bring your own express webserver)
Instead of using the built-in web server for Dapr sidecar to application communication, you can also bring your own instance. This is helpful in scenarios like when you are building a REST API back-end and want to integrate Dapr directly in it.
Note, this is currently available for express only.
💡 Note: when using a custom web-server, the SDK will configure server properties like max body size, and add new routes to it. The routes are unique on their own to avoid any collisions with your application, but it’s not guaranteed to not collide.
import { DaprServer, CommunicationProtocolEnum } from "@dapr/dapr";
import express from "express";
const myApp = express();
myApp.get("/my-custom-endpoint", (req, res) => {
res.send({ msg: "My own express app!" });
});
const daprServer = new DaprServer({
serverHost: "127.0.0.1", // App Host
serverPort: "50002", // App Port
serverHttp: myApp,
clientOptions: {
daprHost
daprPort
}
});
// Initialize subscriptions before the server starts, the Dapr sidecar uses it.
// This will also initialize the app server itself (removing the need for `app.listen` to be called).
await daprServer.start();
After configuring the above, you can call your custom endpoint as you normally would:
const res = await fetch(`http://127.0.0.1:50002/my-custom-endpoint`);
const json = await res.json();
Using gRPC
Since HTTP is the default, you will have to adapt the communication protocol to use gRPC. You can do this by passing an extra argument to the client or server constructor.
import { DaprServer, CommunicationProtocolEnum } from "@dapr/dapr";
const server = new DaprServer({
serverHost: appHost,
serverPort: appPort,
communicationProtocol: CommunicationProtocolEnum.GRPC,
clientOptions: {
daprHost,
daprPort,
},
});
// initialize subscribtions, ... before server start
// the dapr sidecar relies on these
await server.start();
# Using dapr run
dapr run --app-id example-sdk --app-port 50051 --app-protocol grpc -- npm run start
# or, using npm script
npm run start:dapr-grpc
ℹ️ Note: The
app-portis required here, as this is where our server will need to bind to. Dapr will check for the application to bind to this port, before finishing start-up.
Building blocks
The JavaScript Server SDK allows you to interface with all of the Dapr building blocks focusing on Sidecar to App features.
Invocation API
For JavaScript SDK 3.19.0 or later, see the service invocation overview for HTTP and gRPC capabilities.
Listen to an Invocation
import { DaprServer, HttpMethod } from "@dapr/dapr";
import type { DaprInvokerCallbackContent } from "@dapr/dapr";
const daprHost = "127.0.0.1"; // Dapr Sidecar Host
const daprPort = "3500"; // Dapr Sidecar Port of this Example Server
const serverHost = "127.0.0.1"; // App Host of this Example Server
const serverPort = "50051"; // App Port of this Example Server "
async function start() {
const server = new DaprServer({
serverHost,
serverPort,
clientOptions: {
daprHost,
daprPort,
},
});
const callbackFunction = async (data: DaprInvokerCallbackContent) => {
console.log("Received body: ", data.body);
console.log("Received metadata: ", data.metadata);
console.log("Received query: ", data.query);
console.log("Received headers: ", data.headers); // only available in HTTP
return { received: true };
};
await server.invoker.listen("hello-world", callbackFunction, { method: HttpMethod.GET });
// You can now invoke the service with your app id and method "hello-world"
await server.start();
}
start().catch((e) => {
console.error(e);
process.exit(1);
});
Follow receiving invocations for matching startup commands, callback field shapes, response behavior, and existing Express applications. See configuration and usage for custom serialization and failure handling.
PubSub API
For JavaScript SDK 3.19.0 or later, see the publish and subscribe overview to choose a delivery mode. Client-initiated streaming subscriptions do not require a DaprServer.
Subscribe to messages
Register each component/topic pair once before server.start(). This example uses an HTTP listener on port 50002:
import { DaprPubSubStatusEnum, DaprServer } from "@dapr/dapr";
async function start() {
const server = new DaprServer({
serverHost: "127.0.0.1",
serverPort: "50002",
clientOptions: { daprHost: "127.0.0.1", daprPort: "3500" },
});
await server.pubsub.subscribe("pubsub", "orders", async (data) => {
console.log("Order received:", data);
return DaprPubSubStatusEnum.SUCCESS;
});
await server.start();
}
start().catch((e) => {
console.error(e);
process.exit(1);
});
Follow the server subscription guide for the matching dapr run command, gRPC configuration, registration methods, and callback data and headers. See configuration and usage for serialization and shutdown.
Subscribe with SUCCESS/RETRY/DROP status
Return DaprPubSubStatusEnum values rather than response objects. See acknowledgements and retries for status precedence, thrown errors, and an inbound resiliency policy.
Subscribe to messages rule based
Use subscribeWithOptions() to declare routes and subscribeToRoute() to attach handlers. See the content-based routing example.
Subscribe with Wildcards
See wildcard topics for MQTT-style # and + examples and component requirements.
Bulk Subscribe to messages
subscribeBulk() delivers one entry at a time to your callback and builds per-entry acknowledgements. See bulk subscriptions for batching options and HTTP payload limitations.
Dead Letter Topics
Set deadLetterTopic on the source subscription and register a separate consumer for failed messages. See dead-letter topics for the complete example and the limitations of deadLetterCallback.
Bindings API
Receive an Input Binding
import { DaprServer } from "@dapr/dapr";
const daprHost = "127.0.0.1";
const daprPort = "3500";
const serverHost = "127.0.0.1";
const serverPort = "5051";
async function start() {
const server = new DaprServer({
serverHost,
serverPort,
clientOptions: {
daprHost,
daprPort,
},
});
const bindingName = "my-binding-name";
const response = await server.binding.receive(bindingName, async (data: any) =>
console.log(`Got Data: ${JSON.stringify(data)}`),
);
await server.start();
}
start().catch((e) => {
console.error(e);
process.exit(1);
});
For a full guide on output bindings visit How-To: Use bindings.
Configuration API
Configuration is a client-side building block, including in applications that also run a DaprServer. Use a gRPC DaprClient to read settings or subscribe to updates. A configuration subscription receives updates over the client’s gRPC stream; it does not require a server callback route.
Getting a configuration value
Use client.configuration.get(storeName, keys?, metadata?). Follow the configuration how-to guide for client setup and examples using @dapr/dapr 3.19.0 or later.
Subscribing to Key Changes
Use subscribe, subscribeWithKeys, or subscribeWithMetadata on client.configuration. Retain each returned handle and call await subscription.stop() during shutdown, not close(). See the subscription example and client usage guidance for callback behavior, cleanup, and stream failure limitations.