moleculer-http-client
Version:
HTTP client mixin that allows Moleculer services to communicate with remote REST APIs
658 lines (526 loc) • 18 kB
Markdown

[](https://travis-ci.org/moleculerjs/moleculer-http-client) [](https://coveralls.io/github/moleculerjs/moleculer-http-client?branch=master) [](https://raw.githubusercontent.com/moleculerjs/moleculer-http-client/master/LICENSE) [](https://www.npmjs.com/package/moleculer-http-client) [](https://www.npmjs.com/package/moleculer-http-client)
A tiny wrapper around [got](https://www.npmjs.com/package/got) HTTP client that allows [Moleculer](https://moleculer.services/) services to communicate with REST APIs. Why got? Because [reasons](https://github.com/sindresorhus/got#comparison).
- [Service Settings](
- [Service Actions](
- [Service Methods](
- [Usage](
- [Actions](
- [Events](
- [Stream](
- [Cache](
- [Got Instance](
- [Customization](
- [Log Messages](
- [Errors](
- Make HTTP requests from Actions and Events
- Stream data
- Cache data
- Customizable log messages and errors
```
npm install moleculer-http-client --save
```
Use `httpClient` field to configure your got client.
```js
module.exports = {
name: "http",
/**
* Moleculer settings
*/
settings: {
// HTTP client settings
httpClient: {
// Boolean value indicating whether request should be logged or not
logging: true,
// Log request function
logOutgoingRequest: logOutgoingRequest,
// Log response function
logIncomingResponse: logIncomingResponse,
// Format the Response
responseFormatter: "body", // one of "body", "headers", "status", "raw"
// Format the Errors
errorFormatter: errorFormatter,
// Got Client options
defaultOptions: {
// Put here any Got available option that can be used to extend Got client
}
}
},
};
```
HTTP GET action
| Property | Type | Default | Description |
| -------- | ---- | ------- | ----------- |
| `url` | `String`| **required** | URL |
| `opt` | `Object`| **optional** | [Request options](https://www.npmjs.com/package/got#options) |
**Type:** `Promise`, `Stream`
HTTP POST action
| Property | Type | Default | Description |
| -------- | ---- | ------- | ----------- |
| `url` | `String`| **required** | URL |
| `opt` | `Object`| **optional** | [Request options](https://www.npmjs.com/package/got#options) |
| `streamPayload` | `Stream`| **optional** | Stream payload |
> **Note:** When streaming use `ctx.meta` to pass `url` and `opt` and `ctx.params` to pass stream data
**Type:** `Promise`
HTTP PUT action
| Property | Type | Default | Description |
| -------- | ---- | ------- | ----------- |
| `url` | `String`| **required** | URL |
| `opt` | `Object`| **optional** | [Request options](https://www.npmjs.com/package/got#options) |
| `streamPayload` | `Stream`| **optional** | Stream payload |
> **Note:** When streaming use `ctx.meta` to pass `url` and `opt` and `ctx.params` to pass stream data
**Type:** `Promise`
HTTP PATCH action
| Property | Type | Default | Description |
| -------- | ---- | ------- | ----------- |
| `url` | `String`| **required** | URL |
| `opt` | `Object`| **optional** | [Request options](https://www.npmjs.com/package/got#options) |
| `streamPayload` | `Stream`| **optional** | Stream payload |
> **Note:** When streaming use `ctx.meta` to pass `url` and `opt` and `ctx.params` to pass stream data
**Type:** `Promise`
HTTP DELETE action
| Property | Type | Default | Description |
| -------- | ---- | ------- | ----------- |
| `url` | `String`| **required** | URL |
| `opt` | `Object`| **optional** | [Request options](https://www.npmjs.com/package/got#options) |
| `streamPayload` | `Stream`| **optional** | Stream payload |
> **Note:** When streaming use `ctx.meta` to pass `url` and `opt` and `ctx.params` to pass stream data
**Type:** `Promise`
HTTP GET method
| Property | Type | Default | Description |
| -------- | ---- | ------- | ----------- |
| `url` | `String`| **required** | URL |
| `opt` | `Object`| **optional** | [Request options](https://www.npmjs.com/package/got#options) |
**Type:** `Promise`, `Stream`
HTTP POST method
| Property | Type | Default | Description |
| -------- | ---- | ------- | ----------- |
| `url` | `String`| **required** | URL |
| `opt` | `Object`| **optional** | [Request options](https://www.npmjs.com/package/got#options) |
| `streamPayload` | `Stream`| **optional** | Stream payload |
**Type:** `Promise`
HTTP PUT method
| Property | Type | Default | Description |
| -------- | ---- | ------- | ----------- |
| `url` | `String`| **required** | URL |
| `opt` | `Object`| **optional** | [Request options](https://www.npmjs.com/package/got#options) |
| `streamPayload` | `Stream`| **optional** | Stream payload |
**Type:** `Promise`
HTTP PATCH method
| Property | Type | Default | Description |
| -------- | ---- | ------- | ----------- |
| `url` | `String`| **required** | URL |
| `opt` | `Object`| **optional** | [Request options](https://www.npmjs.com/package/got#options) |
| `streamPayload` | `Stream`| **optional** | Stream payload |
**Type:** `Promise`
HTTP DELETE method
| Property | Type | Default | Description |
| -------- | ---- | ------- | ----------- |
| `url` | `String`| **required** | URL |
| `opt` | `Object`| **optional** | [Request options](https://www.npmjs.com/package/got#options) |
**Type:** `Promise`
**Action Example**
```js
const { ServiceBroker } = require("moleculer");
const HTTPClientService = require("moleculer-http-client");
// Create broker
let broker = new ServiceBroker();
// Create a service
broker.createService({
name: "http",
// Load HTTP Client Service
mixins: [HTTPClientService]
});
// Start the broker
broker.start().then(() => {
broker
// Make a HTTP GET request
.call("http.get", {
url: "https://httpbin.org/json",
opt: { responseType: "json" }
})
.then(res => broker.logger.info(res))
.catch(error => broker.logger.error(error));
});
```
**Result**
```bash
INFO http-client/HTTP: => HTTP GET to "https://httpbin.org/json"
INFO http-client/HTTP: <= HTTP GET to "https://httpbin.org/json" returned with status code 200
INFO http-client/BROKER: { slideshow: { author: 'Yours Truly', date: 'date of publication', slides: [ [Object], [Object] ], title: 'Sample Slide Show' } }
```
**Event Example**
```js
const { ServiceBroker } = require("moleculer");
const HTTPClientService = require("moleculer-http-client");
// Create broker
let broker = new ServiceBroker();
// Create a service
broker.createService({
name: "http",
// Load HTTP Client Service
mixins: [HTTPClientService],
events: {
// Register an event listener
async "some.Event"(request) {
this.logger.info("Caught an Event");
// Use service method to make a request
const res = await this._get(request.url, request.opt);
this.logger.info("Printing Payload");
// Print the response data
this.logger.info(res.body);
}
}
});
// Start the broker
broker.start().then(() => {
broker
// Emit some event
.emit("some.Event", {
url: "https://httpbin.org/json",
opt: { responseType: "json" }
});
});
```
**Result**
```bash
INFO http-client/HTTP: Caught an Event
INFO http-client/HTTP: => HTTP GET to "https://httpbin.org/json"
INFO http-client/HTTP: <= HTTP GET to "https://httpbin.org/json" returned with status code 200
INFO http-client/HTTP: Printing Payload
INFO http-client/HTTP: { slideshow: { author: 'Yours Truly', date: 'date of publication', slides: [ [Object], [Object] ], title: 'Sample Slide Show' } }
```
```js
const { ServiceBroker } = require("moleculer");
const HTTPClientService = require("moleculer-http-client");
const fs = require("fs");
// Create broker
let broker = new ServiceBroker({
nodeID: "http-client"
});
// Create a service
broker.createService({
name: "http",
// Load HTTP Client Service
mixins: [HTTPClientService]
});
// Start the broker
broker.start().then(() => {
broker
// Make a HTTP GET request
.call("http.get", {
url: "https://sindresorhus.com/",
opt: { isStream: true }
})
.then(res => {
const filePath = "./examples/stream-get/file.md";
res.pipe(fs.createWriteStream(filePath, { encoding: "utf8" }));
res.on("response", response => {
broker.logger.info(response.statusCode);
});
})
.catch(error => broker.logger.error(error));
});
```
```js
const { ServiceBroker } = require("moleculer");
const HTTPClientService = require("moleculer-http-client");
const ApiGateway = require("moleculer-web");
const fs = require("fs");
// Create broker
let broker = new ServiceBroker({
nodeID: "http-client"
});
// Create a HTTP Client Service
broker.createService({
name: "http",
// Load HTTP Client Service
mixins: [HTTPClientService]
});
// Create HTTP Server Services
broker.createService({
name: "api",
mixins: [ApiGateway],
settings: {
port: 4000,
routes: [
{
path: "/stream",
bodyParsers: { json: false, urlencoded: false },
aliases: { "POST /": "stream:api.postStream" }
}
]
},
actions: {
postStream(ctx) {
return new Promise((resolve, reject) => {
const stream = fs.createWriteStream(
"./examples/stream-post/stored-data.md"
);
stream.on("close", async () => {
resolve({ fileName: `file.md`, method: "POST" });
});
// Return error to the user
stream.on("error", err => {
reject(err);
});
// Pipe the data
ctx.params.pipe(stream);
});
}
}
});
// Start the broker
broker.start().then(() => {
const streamFile = "./examples/stream-post/data-to-stream.md";
const stream = fs.createReadStream(streamFile, { encoding: "utf8" });
// Pass stream as ctx.params
// Pass URL and options in ctx.meta
const req = broker.call("http.post", stream, {
meta: { url: "http://localhost:4000/stream", isStream: true }
});
req.then(res => {
broker.logger.info(res.statusCode);
});
});
```
If you are using [actions](
> Please note that when using Moleculer's cache you will be ignoring [`Cache-Control` header field](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control). If you care about `Cache-Control` then you should use [Got's cache](
**Example of Moleculer Cache**
```js
const { ServiceBroker } = require("moleculer");
const HTTPClientService = require("moleculer-http-client");
// Create broker
let broker = new ServiceBroker({
nodeID: "http-client",
// Enable Moleculer Cache
cacher: "Memory"
});
// Create a service
broker.createService({
name: "http",
// Load HTTP Client Service
mixins: [HTTPClientService],
actions: {
get: {
// Enable cache for GET action
// More info: https://moleculer.services/docs/0.13/caching.html
cache: true
}
}
});
// Start the broker
broker.start().then(() => {
broker
// Make a HTTP GET request
.call("http.get", {
url: "https://httpbin.org/json",
opt: { responseType: "json" }
})
.then(res => broker.logger.info(res.body))
.then(() =>
broker.call("http.get", {
url: "https://httpbin.org/json",
opt: { responseType: "json" }
})
)
.then(res => broker.logger.info(res.body))
.catch(error => broker.logger.error(error));
});
```
**Result**
```bash
INFO http-client/HTTP: => HTTP GET to "https://httpbin.org/json"
INFO http-client/HTTP: <= HTTP GET to "https://httpbin.org/json" returned with status code 200
Request -> INFO http-client/BROKER: { slideshow: { author: 'Yours Truly', date: 'date of publication', slides: [ [Object], [Object] ], title: 'Sample Slide Show' } }
Cache -> INFO http-client/BROKER: { slideshow: { author: 'Yours Truly', date: 'date of publication', slides: [ [Object], [Object] ], title: 'Sample Slide Show' } }
```
If you are using [methods](
**Example of Got cache**
```js
const { ServiceBroker } = require("moleculer");
const HTTPClientService = require("moleculer-http-client");
// Using JS Map as cache
const cacheMap = new Map();
// Create broker
let broker = new ServiceBroker({
nodeID: "http-client"
});
// Create a service
broker.createService({
name: "http",
// Load HTTP Client Service
mixins: [HTTPClientService],
settings: {
httpClient: {
defaultOptions: {
// Set Got's built-in cache
// More info: https://www.npmjs.com/package/got#cache-1
cache: cacheMap
}
}
}
});
// Start the broker
broker.start().then(() => {
broker
// Make a HTTP GET request
.call("http.get", {
url: "https://httpbin.org/cache/150",
opt: { responseType: "json" }
})
.then(res => broker.logger.info(res.isFromCache))
.then(() =>
broker.call("http.get", {
url: "https://httpbin.org/cache/150",
opt: { responseType: "json" }
})
)
.then(res => broker.logger.info(res.isFromCache))
.catch(error => broker.logger.error(error));
});
```
**Result**
```bash
INFO http-client/HTTP: => HTTP GET to "https://httpbin.org/cache/150"
INFO http-client/HTTP: <= HTTP GET to "https://httpbin.org/cache/150" returned with status code 200
INFO http-client/BROKER: false
INFO http-client/HTTP: => HTTP GET to "https://httpbin.org/cache/150"
INFO http-client/HTTP: **CACHED** HTTP GET to "https://httpbin.org/cache/150" returned with status code 200
INFO http-client/BROKER: true
```
If you need to do some fancy request (e.g., `HEAD`, `TRACE`, `OPTIONS`) you can directly call the got client available at `_client`.
```js
const { ServiceBroker } = require("moleculer");
const HTTPClientService = require("moleculer-http-client");
// Create broker
let broker = new ServiceBroker({
nodeID: "http-client"
});
// Create a service
broker.createService({
name: "http",
// Load HTTP Client Service
mixins: [HTTPClientService],
actions: {
async fancyRequest(ctx) {
try {
// Direct call to Got Client
// Can be any Got supported HTTP Method
return await this._client(ctx.params.url, ctx.params.opt);
} catch (error) {
throw error;
}
}
}
});
// Start the broker
broker.start().then(() => {
broker
// Make a fancy request
.call("http.fancyRequest", {
url: "https://httpbin.org/json",
opt: { method: "GET", responseType: "json" }
})
.then(res => broker.logger.info(res.body))
.catch(error => broker.logger.error(error));
});
```
```bash
INFO http-client/HTTP: => HTTP GET to "https://httpbin.org/json"
INFO http-client/HTTP: <= HTTP GET to "https://httpbin.org/json" returned with status code 200
INFO http-client/BROKER: { slideshow: { author: 'Yours Truly', date: 'date of publication', slides: [ [Object], [Object] ], title: 'Sample Slide Show' } }
```
```js
const service = broker.createService({
name: "http",
mixins: [MoleculerHTTP],
settings: {
httpClient: {
// Input is Got's options object. More info: https://www.npmjs.com/package/got#options
logOutgoingRequest: options => {
console.log(`-----> Request ${options.href}`);
},
// Input is Got's response object: More info: https://www.npmjs.com/package/got#response
logIncomingResponse: response => {
console.log(`<----- Response Status Code ${response.statusCode}`);
}
}
}
});
```
```js
const service = broker.createService({
name: "http",
mixins: [MoleculerHTTP],
settings: {
httpClient: {
// Custom error handler function
// Input error is Got's error. More info: https://www.npmjs.com/package/got#errors
errorFormatter: error => {
return new Error("Custom Error");
}
}
}
});
```
```bash
$ npm test
```
Please send pull requests improving the usage and fixing bugs, improving documentation and providing better examples.
The project is available under the [MIT license](https://tldrlegal.com/license/mit-license).
Copyright (c) 2016-2020 MoleculerJS
[](https://github.com/moleculerjs) [](https://twitter.com/MoleculerJS)