npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

moleculer-http-client

v0.4.2

Published

HTTP client mixin that allows Moleculer services to communicate with remote REST APIs

Downloads

1,524

Readme

Moleculer logo

Build Status Coverage Status GitHub license npm Downloads

moleculer-http-client

A tiny wrapper around got HTTP client that allows Moleculer services to communicate with REST APIs. Why got? Because reasons.

Features

  • Make HTTP requests from Actions and Events
  • Stream data
  • Cache data
  • Customizable log messages and errors

Install

npm install moleculer-http-client --save

Service Settings

Use httpClient field to configure your got client.

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
      }
    }
  },
};

Service Actions

get

HTTP GET action

Parameters

| Property | Type | Default | Description | | -------- | ---- | ------- | ----------- | | url | String| required | URL | | opt | Object| optional | Request options |

Returns

Type: Promise, Stream

post

HTTP POST action

Parameters

| Property | Type | Default | Description | | -------- | ---- | ------- | ----------- | | url | String| required | URL | | opt | Object| optional | Request options | | streamPayload | Stream| optional | Stream payload |

Note: When streaming use ctx.meta to pass url and opt and ctx.params to pass stream data

Returns

Type: Promise

put

HTTP PUT action

Parameters

| Property | Type | Default | Description | | -------- | ---- | ------- | ----------- | | url | String| required | URL | | opt | Object| optional | Request options | | streamPayload | Stream| optional | Stream payload |

Note: When streaming use ctx.meta to pass url and opt and ctx.params to pass stream data

Returns

Type: Promise

patch

HTTP PATCH action

Parameters

| Property | Type | Default | Description | | -------- | ---- | ------- | ----------- | | url | String| required | URL | | opt | Object| optional | Request options | | streamPayload | Stream| optional | Stream payload |

Note: When streaming use ctx.meta to pass url and opt and ctx.params to pass stream data

Returns

Type: Promise

delete

HTTP DELETE action

Parameters

| Property | Type | Default | Description | | -------- | ---- | ------- | ----------- | | url | String| required | URL | | opt | Object| optional | Request options | | streamPayload | Stream| optional | Stream payload |

Note: When streaming use ctx.meta to pass url and opt and ctx.params to pass stream data

Returns

Type: Promise

Service Methods

_get

HTTP GET method

Parameters

| Property | Type | Default | Description | | -------- | ---- | ------- | ----------- | | url | String| required | URL | | opt | Object| optional | Request options |

Returns

Type: Promise, Stream

_post

HTTP POST method

Parameters

| Property | Type | Default | Description | | -------- | ---- | ------- | ----------- | | url | String| required | URL | | opt | Object| optional | Request options | | streamPayload | Stream| optional | Stream payload |

Returns

Type: Promise

_put

HTTP PUT method

Parameters

| Property | Type | Default | Description | | -------- | ---- | ------- | ----------- | | url | String| required | URL | | opt | Object| optional | Request options | | streamPayload | Stream| optional | Stream payload |

Returns

Type: Promise

_patch

HTTP PATCH method

Parameters

| Property | Type | Default | Description | | -------- | ---- | ------- | ----------- | | url | String| required | URL | | opt | Object| optional | Request options | | streamPayload | Stream| optional | Stream payload |

Returns

Type: Promise

_delete

HTTP DELETE method

Parameters

| Property | Type | Default | Description | | -------- | ---- | ------- | ----------- | | url | String| required | URL | | opt | Object| optional | Request options |

Returns

Type: Promise

Usage

Actions

Action Example

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

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' } }

Events

Event Example

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

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' } }

Stream

GET Stream

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));
});

POST Stream

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);
  });
});

Cache

Moleculer Cache

If you are using actions to make HTTP requests then you can use Moleculer's cache to cache responses.

Please note that when using Moleculer's cache you will be ignoring Cache-Control header field. If you care about Cache-Control then you should use Got's cache.

Example of Moleculer Cache

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

            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' } }

Got's Cache

If you are using methods or you care about Cache-Control header option then you should use Got's cache.

Example of Got cache

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

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

Got Instance

If you need to do some fancy request (e.g., HEAD, TRACE, OPTIONS) you can directly call the got client available at _client.

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));
});
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' } }

Customization

Log Messages

    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}`);
          }
        }
      }
    });

Errors

    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");
          }
        }
      }
    });

Test

$ npm test

Contribution

Please send pull requests improving the usage and fixing bugs, improving documentation and providing better examples.

License

The project is available under the MIT license.

Contact

Copyright (c) 2016-2020 MoleculerJS

@moleculerjs @MoleculerJS