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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@mikosoft/httpclient-node

v1.1.0

Published

Simple but powerful HTTP client for NodeJS.

Readme

@mikosoft/httpclient-node

A simple but powerful HTTP client for Node.js.

Why? The HTTP Client leverages the HTTP protocol to establish connections with an HTTP server, which can be a web server, API, or another service. Recognizing the lack of an efficient HTTP Client for Node.js, this library was developed specifically for the Node.js environment. It supports both HTTP and HTTPS protocols, ensuring communication and optimized performance.

Features

  • Supports GET, POST, PUT, DELETE, and PATCH methods.
  • Handles retries and timeouts.
  • Supports HTTP and HTTPS requests.
  • Can process redirects (3XX).
  • Supports gzip and deflate decompression.
  • Custom request headers.
  • Optional proxy support.
  • Can return responses as a buffer for file handling.
  • Supports JSON API requests with automatic parsing.
  • Provides request and response streams for piping.

Installation

npm install --save @mikosoft/httpclient-node

Usage

Basic Request

const { HttpClient } = require('@mikosoft/httpclient-node');
const httpClient = new HttpClient();
httpClient.askOnce('https://example.com')
  .then(response => {
    console.log(response.res.content);
  })
  .catch(error => console.error(error));

JSON API Request

httpClient.askJSON('https://api.example.com/data', 'POST', { key: 'value' })
  .then(response => console.log(response.res.content))
  .catch(error => console.error(error));

Handling Streams

const fs = require('fs');
httpClient.grabStreams('https://example.com/file.pdf', 'GET')
  .then(({ clientResponse }) => {
    const fileStream = fs.createWriteStream('file.pdf');
    clientResponse.pipe(fileStream);
  })
  .catch(error => console.error(error));

Options

| Option | Default Value | Description | |---------------|--------------|-------------| | encodeURI | false | Encodes spaces as %20. | | encoding | 'utf8' | Encoding for response content. Use 'binary' for files. | | timeout | 8000 | Request timeout in milliseconds. | | retry | 3 | Number of retry attempts on failure. | | retryDelay | 5000 | Delay between retries in milliseconds. | | maxRedirects | 3 | Number of redirects to follow. | | decompress | false | Enables gzip/deflate decompression. | | bufferResponse | false | Returns response as a buffer instead of a string. | | debug | false | Enables logging. |

const opts = {
  encodeURI: false,
  encoding: 'utf8',
  timeout: 8000,
  retry: 3,
  retryDelay: 5000,
  maxRedirects: 3,
  decompress: false,
  bufferResponse: false,
  debug: false
};

Proxy Support

To use a proxy, pass an instance of https-proxy-agent:

const HttpsProxyAgent = require('https-proxy-agent');
const proxyAgent = new HttpsProxyAgent('http://proxy-server:port');

const clientWithProxy = new HttpClient({}, proxyAgent);
clientWithProxy.ask('https://example.com', 'GET')
  .then(response => console.log(response.res.content));

API

constructor(opts:object, proxyAgent:object)

askOnce(url:string, method:string, body:object, headers:object)

Send one time HTTP/HTTPS request. Redirection is not handled. Response is a Promise so async/await can be used. hcn.askOnce('https://www.dummy-api.com/create', 'POST', {first_name: 'Saša'}, hcn.default_headers);

answer (HTTP response) is formatted as simple object
------------------------------------------------------------
{{
  httpVersion: '1.1',
  https: false,
  req: {
    url: 'http://www.adsuu.com?x=%C4%8Da',
    method: 'GET',
    body: null,
    headers: {
      'user-agent': 'MikoSoft HttpClient-Node/1.0.4',
      accept: '*/*',
      'cache-control': 'no-cache',
      'accept-encoding': 'gzip',
      connection: 'close',
      'content-type': 'text/html; charset=UTF-8'
    },
    query: URLSearchParams { 'x' => 'ča' }
  },
  res: {
    status: 301,
    statusMessage: 'Moved Permanently',
    headers: {
      server: 'nginx/1.17.10 (Ubuntu)',
      date: 'Wed, 12 Mar 2025 10:22:47 GMT',
      'content-type': 'text/html',
      'content-length': '179',
      connection: 'close',
      location: 'https://www.adsuu.com/?x=%C4%8Da'
    },
    content: '<html>\r\n' +
      '<head><title>301 Moved Permanently</title></head>\r\n' +
      '<body>\r\n' +
      '<center><h1>301 Moved Permanently</h1></center>\r\n' +
      '<hr><center>nginx/1.17.10 (Ubuntu)</center>\r\n' +
      '</body>\r\n' +
      '</html>\r\n'
  },
  time: {
    req: '2025-03-12T10:22:47.073Z',
    res: '2025-03-12T10:22:47.291Z',
    duration: 0.218
  },
  opts: {
    encodeURI: true,
    encoding: 'utf8',
    timeout: 8000,
    retry: 3,
    retryDelay: 5000,
    maxRedirects: 3,
    decompress: false,
    bufferResponse: false,
    debug: false
  }
}

ask(url:string, method:string, body:object, headers:object)

Sends HTTP/HTTPS request to HTTP server. Redirection is handled maxRedirects times. Response is an array of resolved responses for every redirection stage. If there's no redirects then this array will contain only one response. hcn.ask('www.yahoo.com');

answers:
-----------------------------
[
  {
    httpVersion: '1.1',
    https: false,
    req: {
      url: 'http://ebay.com',
      method: 'GET',
      body: undefined,
      headers: undefined,
      query: URLSearchParams {}
    },
    res: {
      status: 301,
      statusMessage: 'Moved Permanently',
      headers: {
        server: 'AkamaiGHost',
        'content-length': '0',
        location: 'https://ebay.com/',
        expires: 'Wed, 12 Mar 2025 10:23:56 GMT',
        'cache-control': 'max-age=0, no-cache, no-store',
        pragma: 'no-cache',
        date: 'Wed, 12 Mar 2025 10:23:56 GMT',
        connection: 'close'
      },
      content: 0
    },
    time: {
      req: '2025-03-12T10:23:56.113Z',
      res: '2025-03-12T10:23:56.717Z',
      duration: 0.604
    },
    opts: {
      encodeURI: false,
      encoding: 'utf8',
      timeout: 3000,
      retry: 2,
      retryDelay: 2100,
      maxRedirects: 3,
      decompress: false,
      bufferResponse: false,
      debug: false
    }
  },
  {
    httpVersion: '1.1',
    https: true,
    req: {
      url: 'https://ebay.com/',
      method: 'GET',
      body: undefined,
      headers: undefined,
      query: URLSearchParams {}
    },
    res: {
      status: 301,
      statusMessage: 'Moved Permanently',
      headers: {
        location: 'https://www.ebay.com/',
        'x-ebay-pop-id': 'SLBSLCAZ03',
        server: 'ebay-proxy-server',
        'content-length': '0',
        expires: 'Wed, 12 Mar 2025 10:23:57 GMT',
        'cache-control': 'max-age=0, no-cache, no-store',
        pragma: 'no-cache',
        date: 'Wed, 12 Mar 2025 10:23:57 GMT',
        connection: 'close',
        'strict-transport-security': 'max-age=31536000'
      },
      content: 0
    },
    time: {
      req: '2025-03-12T10:23:56.723Z',
      res: '2025-03-12T10:23:57.973Z',
      duration: 1.25
    },
    opts: {
      encodeURI: false,
      encoding: 'utf8',
      timeout: 3000,
      retry: 2,
      retryDelay: 2100,
      maxRedirects: 3,
      decompress: false,
      bufferResponse: false,
      debug: false
    }
  },
  {
    httpVersion: '1.1',
    https: true,
    req: {
      url: 'https://www.ebay.com/',
      method: 'GET',
      body: undefined,
      headers: undefined,
      query: URLSearchParams {}
    },
    res: {
      status: 200,
      statusMessage: 'OK',
      headers: {
        'x-content-type-options': 'nosniff',
        'x-xss-protection': '1; mode=block',
        'x-frame-options': 'SAMEORIGIN',
        'accept-ch': 'sec-ch-ua-model,sec-ch-ua-platform-version,sec-ch-ua-full-version',
        'content-type': 'text/html; charset=utf-8',
        rlogid: 't6u%60tsodhct%60d13fiiw%3F%3Cqfwrkbkbpfg07%60jhs.22%3Fac1%3F7a%60*e7dae-19589e1e754-0x2305',
        'x-envoy-upstream-service-time': '228',
        server: 'ebay-proxy-server',
        'strict-transport-security': 'max-age=31536000',
        date: 'Wed, 12 Mar 2025 10:23:58 GMT',
        'transfer-encoding': 'chunked',
        connection: 'close, Transfer-Encoding',
        'set-cookie': [Array]
      },
      content: 353695
    },
    time: {
      req: '2025-03-12T10:23:57.975Z',
      res: '2025-03-12T10:23:58.960Z',
      duration: 0.985
    },
    opts: {
      encodeURI: false,
      encoding: 'utf8',
      timeout: 3000,
      retry: 2,
      retryDelay: 2100,
      maxRedirects: 3,
      decompress: false,
      bufferResponse: false,
      debug: false
    }
  }
]

askJSON(url, method = 'GET', body)

Send HTTP/HTTPS request to API with JSON response. Redirection is not handled because we suppose that APIs are not using redirections. Parameter body can be either string or object type. As HTTP Client receives responses as string it will be automatically converted into object. hcn.askJSON('http://dummy.restapiexample.com/api/v1/employees');

// default JSON headers
{
  'content-type': 'application/json; charset=utf-8',
  'accept': 'application/json'
}
JSON answer:
----------------------------------------
{
  httpVersion: '1.1',
  https: false,
  req: {
    url: 'http://dummy.restapiexample.com/api/v1/employees',
    method: 'GET',
    body: {},
    headers: {
      'content-type': 'application/json; charset=utf-8',
      accept: 'application/json'
    },
    query: URLSearchParams {}
  },
  res: {
    status: 409,
    statusMessage: 'Conflict',
    headers: {
      date: 'Wed, 12 Mar 2025 10:25:57 GMT',
      server: 'Apache',
      'content-length': '83',
      connection: 'close',
      'content-type': 'text/html; charset=iso-8859-1'
    },
    content: '<script>document.cookie = "humans_21909=1"; document.location.reload(true)</script>'
  },
  time: {
    req: '2025-03-12T10:25:56.910Z',
    res: '2025-03-12T10:25:57.698Z',
    duration: 0.788
  },
  opts: {
    encodeURI: false,
    encoding: 'utf8',
    timeout: 3000,
    retry: 1,
    retryDelay: 1300,
    maxRedirects: 3,
    decompress: false,
    bufferResponse: false,
    debug: false
  }
}

grabStreams(url:string, method:string, body:object, headers:object)

Get request and response streams which can be used for piping. For example: const = { clientRequest, clientResponse } = hcn.grabStreams('https://www.example.com/song.mp4'); clientResponse.pipe(...);

// send request to telegram
  const opts = {
    encodeURI: false,
    encoding: 'utf8',
    timeout: 8000,
    retry: 0,
    retryDelay: 5500,
    maxRedirects: 0,
    decompress: false,
    bufferResponse: false,
    debug: false
  };
  const hcn = new HttpClient(opts);
  const { clientRequest, clientResponse } = await hcn.grabStreams(`https://api.telegram.org/file/bot${BOT_TOKEN}/${telegram_file_path}`);

  // save file
  const filePath = path.join(process.cwd(), './tmp/proc-pdf', username, fileName);
  await fse.ensureFile(filePath);
  const writer = fse.createWriteStream(filePath);
  clientResponse.pipe(writer);

  // writer events
  writer.on('finish', () => {
    console.log(`File downloaded successfully: ${fileName}`);
  });

  writer.on('error', (err) => {
    console.error(`Error writing file: ${err}`);
  });

print(obj)

Print the object in the console. Use it to debug the answer.

AddOns

Additional libraries.

RobotsTxt

const { HttpClient, RobotsTxt } = require('@mikosoft/httpclient-node');
const robotsTxt = new RobotsTxt(HttpClient);

const fja = async () => {
  const url = 'https://www.yahoo.com/lifestyle/mom-makes-upsetting-discovery-walmart-134505752.html';
  const robotsText = await robotsTxt.fetch(url);
  console.log('robotsText::');
  console.log(robotsText);

  const robotsTextObj = robotsTxt.parse(robotsText);
  console.log('robotsTextObj::', robotsTextObj);

  const follow_urls = robotsTxt.whatToFollow(robotsTextObj, '*');
  console.log('follow_urls::', follow_urls);

  const unfollow_urls = robotsTxt.whatToUnfollow(robotsTextObj, '*');
  console.log('unfollow_urls::', unfollow_urls);
};

fja();

License

MIT