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 🙏

© 2026 – Pkg Stats / Ryan Hefner

rest-envelop

v1.0.1

Published

Wrapper for working with REST API using well-known axios and node-fetch modules

Readme

Wrapper for working with REST API using well-known axios and node-fetch modules

Content

About
Config Initialization REST clients use Requests execution result More about request options

About The wrapper extends and facilitates the work with modules.

  • Inspired by the caching implementation in Apollo GraphQL Server, where the keys are urls with parameters, this was added here, but also left the option to specify the key yourself. Additionally, caching is performed only for responses with specific response statuses that you specify. You can use both Memcached and Redis for data storage.

  • It also has the functionality to repeat requests (retry) when receiving statuses that are not expected to be successful.

  • Added the ability to create a node-fetch instance like axios.create({})

  • Added timeout support to node-fetch using AbortController

Config

// config/default.js

const pkg = require('../package.json');

module.exports = {
    app: {
        name: pkg.name,
        version: pkg.version,
        env: process.env.NODE_ENV,
    },
    cacheServices: {
        redis: {
            port: 6379,
            host: '127.0.0.1',
            db: 5,
        },
        memcached: {
            servers: ['127.0.0.1:11211'],
            options: {
                retries: 5,
                retry: 5000,
                remove: true,
                failOverServers: ['127.0.0.1:11214', '127.0.0.1:11215'],
            },
        },
    },
    rest: {
        jsonPlaceholder: {
            schema: 'https',
            hostname: 'jsonplaceholder.typicode.com'
        }
    }
}

Initialization

// helpers/init.js

const config = require('config');
const { Axios, Fetch } = require('rest-envelop');

const { app, cacheServices, rest: { jsonPlaceholder } } = config;

const requestUrl = `${jsonPlaceholder.schema}://${jsonPlaceholder.hostname}`;
const configs = {
    // baseURL: requestUrl,
    timeout: 1000,
    headers: {
        'X-Request-Source': `${app.name}:${app.version}`
    },
    optional: {
        environment: app.env,
        // requestLog: true,
        // createInstance: true,
        cacheService: {
            cachedStatuses: [200],
            redis: cacheServices.redis,
            // memcached: cacheServices.memcached,
        },
    },
};

// who prefers axios
const axios = new Axios(configs);
// who prefers node-fetch
const fetch = new Fetch(configs);

module.exports = { 
    axios, 
    fetch,
};

REST clients use

// clients/jsonPlaceholder.js

const config = require('config');

const { axios, fetch } = require('../helpers/init.js')

const { rest: { jsonPlaceholder } } = config;

// if 'createInstance: true' is not specified in init.js, we need the url for the request here
const requestUrl = `${jsonPlaceholder.schema}://${jsonPlaceholder.hostname}`;
// API paths for requests
const paths = {
    todos: 'todos',
    comments: 'comments',
    users: 'users',
    posts: 'posts',
};
// cache ttl
const ttl = {
    tenMin: 10 * 60,
    thirtyMin: 30 * 60,
    oneHour: 60 * 60
};

module.exports = {
    // USING AXIOS WITHOUT CREATING AN INSTANCE
    async todos(){
        return axios.request(`${requestUrl}/${paths.todos}`, {
            method: 'GET',
            params: { completed: true, userId: 7 },
            // requestLog: true,
            retry: {
                attempts: 3,
                expectedStatuses: [200, 201],
            },
            cache: {
                ttl: ttl.tenMin,
                // cachedStatuses: [200],
                // key: `${paths.todos}_${completed}_true_userId_7}`,
            },
        })
    },

  // USING AXIOS WITH CREATED AN INSTANCE
  async comments(){
        return axios.request(`/${paths.comments}`, {
          method: 'GET',
          params: { postId: 5 },
          // requestLog: true,
          cache: {
            ttl: ttl.thirtyMin,
            // cachedStatuses: [200],
            // key: `${paths.comments}_postId_5}`,
          },
        })
  },

  // USING FETCH WITHOUT CREATING AN INSTANCE
  async users(){
        return fetch.request(`${requestUrl}/${paths.users}`, {
          method: 'GET',
          cache: {
            ttl: ttl.thirtyMin,
          },
        })
  },

  // USING FETCH WITH CREATED AN INSTANCE
  async createPost(){
        return fetch.request(`/${paths.posts}`, {
          method: 'POST',
          body: JSON.stringify({
            title: 'foo',
            body: 'bar',
            userId: 1,
          }),
          headers: {
            'Content-Type': 'application/json',
          },
        })
  }
}

Requests execution result The result of the request is a format object:

{
  data,
  status,
  headers
}
  • data — response body
  • status — http response status code
  • headers — response headers (if the data is returned from the cache, then this field is missing)

When you execute requests and logged them in the terminal, you will see the following (the display and format are borrowed from Apollo GraphQL Server):

[/rest-service]
> node index.js
GET 200: https://jsonplaceholder.typicode.com/todos?completed=true&userId=7 (142 ms.)
GET 200: https://jsonplaceholder.typicode.com/comments?postId=5 (43 ms.)
GET 200: https://jsonplaceholder.typicode.com/users? (36 ms.)
POST 201: https://jsonplaceholder.typicode.com/posts? (506 ms.)

If the requests have already been executed and caching is enabled, the logs will be slightly different:

[/rest-service]
> node index.js
GET: https://jsonplaceholder.typicode.com/todos?completed=true&userId=7 (cached)
GET: https://jsonplaceholder.typicode.com/comments?postId=5 (cached)
GET: https://jsonplaceholder.typicode.com/users? (cached)
POST 201: https://jsonplaceholder.typicode.com/posts? (544 ms.)

Usually POST requests are not cached, but if you need it, you can do it, so by passing the necessary parameters for caching

The info below demonstrates a request using the retry option:

[/rest-service]
> node index.js
Attempt 1/3 failed for GET https://jsonplaceholder.typicode.com/todos_?completed=true&userId=7: Request failed with status code 404
Attempt 2/3 failed for GET https://jsonplaceholder.typicode.com/todos_?completed=true&userId=7: Request failed with status code 404
Attempt 3/3 failed for GET https://jsonplaceholder.typicode.com/todos_?completed=true&userId=7: Request failed with status code 404
Failed to fetch after 3 attempts for https://jsonplaceholder.typicode.com/todos_?completed=true&userId=7

It is set for a specific request and looks like this:

{
  retry: {
    { 
      attempts: 3,
      expectedStatuses: [200, 201],
    }
}

How it works: if the API response status does not match the expectedStatuses, then we will make requests in the number of attempts

More about request options You may notice that some options are the same in the instance created in helpers/init.js and in individual requests.

If the option is checked when creating an instance, it means that it will be applied to all requests. If it is not set when creating an instance, but is set for a specific request, then it will work only for this request