Skip to main content

Actions

The actions are the callable/public methods of the service. The action calling represents a remote-procedure-call (RPC). It has request parameters & returns response, like a HTTP request.

If you have multiple instances of services, the broker will load balance the request among instances.

action-balancing

Call services

To call a service use the broker.call method. The broker looks for the service (and a node) which has the given action and call it. The function returns a Promise.

Syntax

const res = await broker.call(actionName, params, opts);

The actionName is a dot-separated string. The first part of it is the service name, while the second part of it represents the action name. So if you have a posts service with a create action, you can call it as posts.create.

The params is an object which is passed to the action as a part of the Context. The service can access it via ctx.params. It is optional. If you don't define, it will be {}.

The opts is an object to set/override some request parameters, e.g.: timeout, retryCount. It is optional.

Available calling options:

NameTypeDefaultDescription
timeoutNumbernullTimeout of request in milliseconds. If the request is timed out and you don't define fallbackResponse, broker will throw a RequestTimeout error. To disable set 0. If it's not defined, the requestTimeout value from broker options will be used.
retriesNumbernullCount of retry of request. If the request is timed out, broker will try to call again. To disable set 0. If it's not defined, the retryPolicy.retries value from broker options will be used.
fallbackResponseAnynullReturns it, if the request has failed.
nodeIDStringnullTarget nodeID. If set, it will make a direct call to the specified node.
metaObject{}Metadata of request. Access it via ctx.meta in actions handlers. It will be transferred & merged at nested calls, as well.
parentCtxContextnullParent Context instance. Use it to chain the calls.
requestIDStringnullRequest ID or Correlation ID. Use it for tracing.

Usages

Call without params

const res = await broker.call("user.list");

Call with params

const res = await broker.call("user.get", { id: 3 });

Call with calling options

const res = await broker.call("user.recommendation", { limit: 5 }, {
timeout: 500,
retries: 3,
fallbackResponse: defaultRecommendation
});

Call with promise error handling

broker.call("posts.update", { id: 2, title: "Modified post title" })
.then(res => console.log("Post updated!"))
.catch(err => console.error("Unable to update Post!", err));

Direct call: get health info from the "node-21" node

const res = await broker.call("$node.health", null, { nodeID: "node-21" })

Metadata

Send meta information to services with meta property. Access it via ctx.meta in action handlers. Please note that in nested calls the meta is merged.

tip

When writing REST APIs, you can obtain the current user session from ctx.meta.user. If you want to access ctx.meta.user within the action being called, you need to manually pass it in.

const res = await this.broker.call('objectql.find', 
{
objectName: 'accounts',
query: {
fields: ['name', 'owner'],
filters: ['owner', '=', ctx.meta.user.userId],
sort: 'name desc'
},
},
{
meta:{
user: ctx.meta.user
}
}
);

Streaming

Moleculer supports Node.js streams as request params and as response. Use it to transfer an incoming file from a gateway, encode/decode or compress/decompress streams.

Examples

Send a file to a service as a stream

const stream = fs.createReadStream(fileName);

broker.call("storage.save", stream, { meta: { filename: "avatar-123.jpg" }});

Please note, the params should be a stream, you cannot add any additional variables to the params. Use the meta property to transfer additional data.

Receiving a stream in a service

module.exports = {
name: "storage",
actions: {
save(ctx) {
// Save the received stream to a file
const s = fs.createWriteStream(`/tmp/${ctx.meta.filename}`);
ctx.params.pipe(s);
}
}
};

Return a stream as response in a service

module.exports = {
name: "storage",
actions: {
get: {
params: {
filename: "string"
},
handler(ctx) {
return fs.createReadStream(`/tmp/${ctx.params.filename}`);
}
}
}
};

Process received stream on the caller side

const filename = "avatar-123.jpg";
broker.call("storage.get", { filename })
.then(stream => {
const s = fs.createWriteStream(`./${filename}`);
stream.pipe(s);
s.on("close", () => broker.logger.info("File has been received"));
})

AES encode/decode example service

const crypto = require("crypto");
const password = "moleculer";

module.exports = {
name: "aes",
actions: {
encrypt(ctx) {
const encrypt = crypto.createCipher("aes-256-ctr", password);
return ctx.params.pipe(encrypt);
},

decrypt(ctx) {
const decrypt = crypto.createDecipher("aes-256-ctr", password);
return ctx.params.pipe(decrypt);
}
}
};