Moleculer HTTP Client Mixin
This package provides an HTTP client mixin for Moleculer microservices, enabling them to make requests to external REST APIs. It is currently at version 0.4.2 and wraps the popular `got` library for HTTP requests. While there's no explicit release cadence stated for this particular mixin, it generally follows the Moleculer ecosystem's development pace. Its key differentiators include seamless integration into Moleculer services via mixins, providing declarative HTTP actions (`get`, `post`, `put`, `patch`), and centralized configuration for logging, error handling, and `got` options within the service settings. This approach simplifies HTTP communication within a microservice architecture, abstracting common concerns like request/response logging and error formatting directly into the service lifecycle.
Common errors
-
Service 'myService' has no action 'myService.get'
cause The `HttpClientMixin` was not correctly added to the service's `mixins` array, or the service name used in `ctx.call` (e.g., 'myService') does not match the actual name of the service that has the mixin.fixVerify that `mixins: [HttpClientMixin]` is present in your service definition. Ensure that the service name in `ctx.call` (e.g., `ctx.call('yourServiceName.get', ...)`) precisely matches the `name` property of your service. -
RequestError: connect ECONNREFUSED
cause This error indicates a network connection issue. The target API server is either not running, unreachable from where your Moleculer service is hosted, or the URL specified in the request is incorrect or malformed.fixDouble-check the URL for typos, verify that the target API is accessible (e.g., ping the host) from your Moleculer service's environment, and ensure no firewalls or network configurations are blocking the outbound connection. -
TypeError: Cannot read properties of undefined (reading 'httpClient')
cause The `httpClient` configuration object within the service `settings` is missing or malformed, preventing the mixin from properly initializing `got` options.fixEnsure your service definition includes a `settings` block with a properly structured `httpClient` object, for example: `settings: { httpClient: { logging: true, defaultOptions: {} } }`. All keys within `httpClient` should be correctly spelled.
Warnings
- gotcha When performing streaming requests (e.g., POST/PUT/PATCH with `streamPayload`), the `url` and `opt` parameters must be passed in `ctx.meta`, while the stream data itself is passed directly as `ctx.params`. This deviates from typical Moleculer action parameter conventions where `ctx.params` usually holds all explicit arguments.
- gotcha This mixin relies on the `got` HTTP client. Breaking changes in `got`'s major versions (e.g., `got@11` to `got@12`) might introduce incompatibilities or require configuration adjustments within `httpClient.defaultOptions` or action parameters, even if `moleculer-http-client`'s own version doesn't change significantly.
- gotcha Unhandled promise rejections from HTTP requests can crash your Moleculer service if not properly caught. Network errors, API errors (e.g., 4xx, 5xx responses), and timeouts from `got` will result in rejected promises.
Install
-
npm install moleculer-http-client -
yarn add moleculer-http-client -
pnpm add moleculer-http-client
Imports
- HttpClientMixin
const HttpClientMixin = require('moleculer-http-client');import HttpClientMixin from 'moleculer-http-client';
Quickstart
import { ServiceBroker } from 'moleculer';
import HttpClientMixin from 'moleculer-http-client';
const broker = new ServiceBroker({
logger: true, // Enable console logger
logLevel: 'info' // Set logging level
});
broker.createService({
name: "myApiConsumer",
mixins: [HttpClientMixin],
settings: {
httpClient: {
logging: true, // Log outgoing requests and incoming responses
responseFormatter: "body", // Only return the response body by default
defaultOptions: {
// Default options passed directly to the 'got' client
headers: {
'User-Agent': 'moleculer-http-client-example/1.0',
},
timeout: {
request: 5000 // 5 seconds timeout for all requests
}
}
}
},
actions: {
async fetchPosts(ctx) {
this.logger.info(`Attempting to fetch post from: ${ctx.params.url}`);
try {
// Call the 'get' action provided by the mixin
const response = await ctx.call("myApiConsumer.get", {
url: "https://jsonplaceholder.typicode.com/posts/1"
});
this.logger.info("Successfully fetched post:", JSON.stringify(response));
return response;
} catch (error) {
this.logger.error("Error fetching post:", error.message);
throw error; // Re-throw to propagate error in Moleculer
}
},
async submitData(ctx) {
this.logger.info(`Attempting to submit data to: ${ctx.params.url}`);
try {
// Call the 'post' action provided by the mixin
const response = await ctx.call("myApiConsumer.post", {
url: "https://jsonplaceholder.typicode.com/posts",
json: {
title: 'foo',
body: 'bar',
userId: 1,
}
});
this.logger.info("Successfully submitted data (ID: %s)", response.id);
return response;
} catch (error) {
this.logger.error("Error submitting data:", error.message);
throw error;
}
}
}
});
async function runExample() {
await broker.start();
broker.logger.info("Broker started. Calling fetchPosts action...");
await broker.call("myApiConsumer.fetchPosts", { url: "https://jsonplaceholder.typicode.com/posts/1" });
broker.logger.info("\nCalling submitData action...");
await broker.call("myApiConsumer.submitData", { url: "https://jsonplaceholder.typicode.com/posts" });
await broker.stop();
}
runExample();