Cloud Native 18 min read

Getting Started with Dapr: Build Cloud‑Native Node.js Microservices from Scratch

This step‑by‑step guide shows how to install the Dapr CLI, initialize local Redis and Zipkin containers, configure component files, and use Dapr’s APIs to perform service invocation, state management, pub/sub, bindings, and secrets management in a Node.js microservice application, complete with code snippets and Docker commands.

Hacker Afternoon Tea
Hacker Afternoon Tea
Hacker Afternoon Tea
Getting Started with Dapr: Build Cloud‑Native Node.js Microservices from Scratch

Install Dapr CLI

macOS (Dapr 1.8):

sudo curl -fsSL https://raw.githubusercontent.com/dapr/cli/master/install/install.sh | /bin/bash

Linux/Windows installation instructions are available at the official documentation URL:

https://docs.dapr.io/getting-started/install-dapr-cli/

Initialize Dapr locally

The dapr init command creates the following resources:

A Redis container for state storage and pub/sub.

A Zipkin container for tracing.

A default components folder with YAML definitions for state, pub/sub, and tracing.

A Dapr placement service container for actor support.

Run the initialization CLI command

dapr init

Verify Dapr version

dapr -v
CLI version: 1.8.0
Runtime version: 1.8.0

Validate running containers

After dapr init the containers daprio/dapr, openzipkin/zipkin and redis should be running. Verify with Docker commands such as docker ps or by inspecting the images.

Use Dapr HTTP API

Run a Dapr sidecar

dapr run --app-id myapp --dapr-http-port 3500

This starts a sidecar listening on port 3500 for the application myapp. The default component definitions created by dapr init are used.

Save state

curl -X POST -H "Content-Type: application/json" -d '[{ "key": "name", "value": "Bruce Wayne"}]' http://localhost:3500/v1.0/state/statestore

Get state

curl http://localhost:3500/v1.0/state/statestore/name

Inspect state in Redis

docker exec -it dapr_redis redis-cli
keys *
"myapp||name"
hgetall "myapp||name"
exit

Delete state

curl -v -X DELETE -H "Content-Type: application/json" http://localhost:3500/v1.0/state/statestore/name

Hands‑on examples

1. Service Invocation

Clone the quickstarts repository and run the order‑processor service with Dapr:

git clone https://github.com/dapr/quickstarts.git
cd service_invocation/javascript/http/order-processor
npm install
dapr run --app-port 5001 --app-id order-processor --app-protocol http --dapr-http-port 3501 -- npm start

In a separate terminal, start the checkout service:

cd ../../checkout
npm install
dapr run --app-id checkout --app-protocol http --dapr-http-port 3500 -- npm start

Service calls are made by adding the dapr-app-id header to HTTP requests:

let axiosConfig = { headers: { "dapr-app-id": "order-processor" } };
const res = await axios.post(`${DAPR_HOST}:${DAPR_HTTP_PORT}/orders`, order, axiosConfig);
console.log("Order passed: " + res.config.data);

2. State Management

Navigate to the state‑management example, install dependencies, and run the service with a Dapr sidecar:

cd state_management/javascript/sdk/order-processor
npm install
dapr run --app-id order-processor --components-path ../../../components/ -- npm run start

JavaScript SDK code that saves, retrieves, and deletes an order in the Redis‑backed statestore component:

const client = new DaprClient(DAPR_HOST, DAPR_HTTP_PORT);
client.state.save(STATE_STORE_NAME, [{ key: orderId.toString(), value: order }]);
client.state.get(STATE_STORE_NAME, orderId.toString()).then(val => console.log("Getting Order:", val));
client.state.delete(STATE_STORE_NAME, orderId.toString());

3. Pub/Sub

Run the order‑processor subscriber:

dapr run --app-port 5001 --app-id order-processing --app-protocol http --dapr-http-port 3501 --components-path ../../../components -- npm run start

Run the checkout publisher:

dapr run --app-id checkout --app-protocol http --dapr-http-port 3500 --components-path ../../../components -- npm run start
await client.pubsub.publish(PUBSUB_NAME, PUBSUB_TOPIC, order);
console.log("Published data: " + JSON.stringify(order));

Pub/sub component definition ( pubsub.yaml) used by the example:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: order_pub_sub
spec:
  type: pubsub.redis
  version: v1
  metadata:
  - name: redisHost
    value: localhost:6379
  - name: redisPassword
    value: ""

4. Input and Output Bindings

Start the PostgreSQL Docker container defined in bindings/db/docker‑compose.yml:

cd bindings/db
docker compose up

Run the Cron binding that triggers a batch job every 10 seconds:

cd bindings/javascript/sdk/batch
npm install
dapr run --app-id batch-sdk --app-port 5002 --dapr-http-port 3500 --components-path ../../../components -- node index.js

Batch job reads orders.json, builds an INSERT statement, and sends it to the PostgreSQL output binding ( binding‑postgres.yaml):

async function processBatch() {
  const orders = JSON.parse(fs.readFileSync('../../orders.json', 'utf8')).orders;
  orders.forEach(order => {
    const sqlCmd = `insert into orders (orderid, customer, price) values (${order.orderid}, '${order.customer}', ${order.price});`;
    const payload = { sql: sqlCmd };
    client.binding.send(postgresBindingName, "exec", "", payload);
  });
}

Cron binding component ( binding‑cron.yaml) definition:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: cron
  namespace: quickstarts
spec:
  type: bindings.cron
  version: v1
  metadata:
  - name: schedule
    value: "@every 10s"

PostgreSQL output binding component ( binding‑postgres.yaml) definition:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: sqldb
  namespace: quickstarts
spec:
  type: bindings.postgres
  version: v1
  metadata:
  - name: url
    value: "user=postgres password=docker host=localhost port=5432 dbname=orders pool_min_conns=1 pool_max_conns=10"

5. Secrets Management

Local file‑based secret store component ( local‑secret‑store.yaml):

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
  name: localsecretstore
  namespace: default
spec:
  type: secretstores.local.file
  version: v1
  metadata:
  - name: secretsFile
    value: secrets.json
  - name: nestedSeparator
    value: ":"

Secret definition ( secrets.json): { "secret": "YourPasskeyHere" } JavaScript SDK code that retrieves the secret:

const DAPR_SECRET_STORE = "localsecretstore";
const SECRET_NAME = "secret";
async function main() {
  const secret = await client.secret.get(DAPR_SECRET_STORE, SECRET_NAME);
  console.log("Fetched Secret: " + JSON.stringify(secret));
}

Official example repository

All demo source code is available at:

https://github.com/dapr/quickstarts.git

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

cloud nativemicroservicesState Managementnodejsdaprsecretspubsubbindings
Hacker Afternoon Tea
Written by

Hacker Afternoon Tea

You might find something interesting here ^_^

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.