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

redux-request-manager

v1.1.0

Published

A tool for storing a tree of redux request history and throttling requests

Downloads

9

Readme

Redux Request Manager

CircleCI

Attaches a lightweight object to window which tracks request history as a tree and provides a simple interface for tracking actions going out through redux-api-middleware or internally.

Event timestamps are stored as ISO strings, and request ids (or, if none exist, 'GLOBAL') as well as action argument values are nested in the tree.

An example window.actionLogs object looks something like this:

{
  "SOME_ACTION": {
     "ID_46": { "REQUEST": "2016-10-06T23:38:46.637Z" },
  },
  "OTHER_ACTION": {
    "ID_46": {
     "SPECIFYINGVALUE1_VALUE2": "2016-10-06T23:38:45.872Z",
    }
  },
  "ACTION_WITHOUT_ID": {
    "GLOBAL": {
      "REQUEST": "2016-10-06T23:38:44.980Z",
      "SUCCESS": "2016-10-06T23:38:45.776Z"
    }
  },
  "NON_API_ACTION_WITHOUT_ID": {
    "GLOBAL": {
      "SPECIFIER1_SPECIFIER2": "2016-10-06T23:38:44.873Z"
    }
  }
}

After the first request has been made with the manager, this object should be universally accessible, and all instances of the request manager will save to and perform checks on this global tree.

Notes on usage

This window-attached tree of request history is obviously inherently insecure. If a public history of which actions have been called when is not appropriate for your app, don't dispatch those actions from the manager, and ignore them in the tracking reducer. However, since this mostly just stores times of requests, the information is generally not a risk to expose.

Also note that redux-request-manager looks in the meta object of API requests/responses to determine which ID to store in the tree. For the below action, the manager would assume the ID is "some-id":

{
  [CALL_API]: {
    types: [
       { type: 'SOME_REQUEST', meta: { id: 'some-id' }, ... },
       // ...
    ]
  }
}

For help producing a request object with meta information, this repo provides an asyncRequestObject helper function.

Getting started

npm install --save redux-request-manager

Incorporating the RequestManager

Add this to your reducers file:

import RequestManager from 'redux-request-manager';

// ...

combineReducers({
  someReducer: reducerFunction,
  rm: RM.actionTrackerReducer([
    'ARRAY', 'OF', 'ACTIONS', 'NOT', 'TO', 'BE', 'TRACKED'
  ])
})

This will add a reducer function which tracks every action that hits your store -- both local action and API requests, successes, and failures.

Unfortunately, there can be a bit of a delay for the action to hit the store and come back to your component, so if you need to throttle or stop dispatches (say, to a slow API), you'll also want to dispatch using the request manager, like so:

import { connect } from 'react-redux';

import { someApiAction } from '../actions';
import RM from 'redux-request-manager';

function SomeComponent ({ dispatch }) {
  const rm = new RM(dispatch);
  const onClick = () => { rm.dispatch(someApiAction()) };

  return (
    // Component here
  );
}

This will call dispatch and simultaneously store a record of the request, before the redux store has been hit.

Other Methods

Primary Public API

dispatchIfHaventAlready(actionObj)

Ensures that the action is only dispatched if it hasn't been before.

// Will only dispatch once
[0, 1, 2].forEach(() => {
  rm.dispatchIfHaventAlready(apiAction())
})

// Will dispatch 3 times -- once with each number argument, without repeating
[0, 1, 2, 0, 1, 2].forEach((number) => {
  rm.dispatchIfHaventAlready(apiAction(number))
})

haventRequestedRecently(actionObj, secondsCutoff)

Returns bool for whether the request has been made in within the given cutoff (defaults to 40s), or the requestThrottleSeconds number passed in at initialization.

const rm = new RequestManager(dispatch, { requestThrottleSeconds: 5 });

// True if it's been requested in last 5 seconds
rm.haveRequestedRecently(apiAction(number));

haveSucceededSinceCutoff(actionObj, secondsCutoff)

Returns bool for whether the request has succeeded within the given cutoff (defaults to 300s), or the freshnessCutoffSeconds number passed in at initialization.

const rm = new RequestManager(dispatch, { freshenessCutoffSeconds: 120 });

// True if it's succeeded in the last two minutes
rm.haveSucceededSinceCutoff(apiAction(number));

flattenedLogs(object)

Returns a flat array representing all actions dispatched.

// Defaults to logging the window.actionLogs object, but can be
// given a different object, as well as a second arg which will be prepended
// to each element in the flattened log
rm.flattenedLogs()

Path Logging Functions

writeLog(objectPath, timestamp)

Given a string object-notation path to the logging location and a timestampt for that action, logs it to the actionLogs object.

// ie a log for a successful API hit for SOME_ACTION for user 36
rm.writeLog('36.SOME_ACTION.SUCCESS', "2017-01-06T19:59:02.323Z");

findLog(objectPath)

Returns the timestamp for a given action, if found.

rm.findLog('36.SOME_ACTION.SUCCESS') // "2017-01-06T19:59:02.323Z"

removeLog(objectPath)

Deletes the log at the given path from the actionLogs object, erasing history of that request.

writeLogFromAction(action)

Like writeLog, but takes an action and infers the path. Takes timestamp from action.now or sets it to the current ISO string.

findLogFromAction(action, specifiedEnd)

Like findLog, but takes an action and action ending (ie 'REQUEST' or 'SUCCESS'), and finds the log for that event for that action.

pathToLogFromAction(action)

Given an action, returns the path to its timestamp in the window.actionLogs object. Takes synchronous actions, returning async actions, or emitting asyncActions (with an array of objects defining type). In this last case, it returns the path to the 'REQUEST' timestamp.

Separate imports

Several additional helper methods are exported alongside the RequestManager class:

Action creator functions

asyncRequestObject

Takes as type string base, an endpoint, and an options object, and returns an FSAA.

import { asyncRequestObject } from 'redux-request-manager';

const requestGithub = (owner, repo) => asyncActionObject(
  'GITHUB_REPO',
  `https://api.github.com/repos/${owner}/${repo}`,
  {
    meta: { id: repo } // Will be stored by RequestManager under this ID
    // other keys include
    // - headerAdditions (ContentType and Accept) pre-set
    // - data object
    // - method (defaults to 'GET')
  }
);

// In a component -- sets whole react-api-middleware chain going
dispatch(requestGithub('sashafklein', 'redux-request-manager'))

Action parser functions

getResponseTypesFromAction(apiAction)

Given an API action, returns an array of type strings.

import { getResponseTypesFromAction } from 'redux-request-manager';
const responseTypes = getResponseTypesFromAction(apiAction(1));
responseTypes.map(type => type.split('_')[1]); // ['REQUEST', 'SUCCESS', 'FAILURE']

parseActionType(typeString)

Given a type string, returns an object with its base and end.

getIDFromAction(apiAction)

Assuming an ID attached to the meta of the response, parses out that ID.